Skip to content

Commit

Permalink
✨ add GPIO interrupt(s) (#1159)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting authored Jan 15, 2025
2 parents 835a17c + 93cb7d3 commit 8603c0d
Show file tree
Hide file tree
Showing 34 changed files with 594 additions and 1,255 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 15.01.2025 | 1.10.9.7 | :sparkles: add GPIO interrupt(s); :warning: remove XIRQ controller, constrain GPIO input/output ports from 64-bit to 32-bit | [#1159](https://github.com/stnolting/neorv32/pull/1159) |
| 13.01.2025 | 1.10.9.6 | add WDT and OCD rest outputs to top module | [#1152](https://github.com/stnolting/neorv32/pull/1152) |
| 11.01.2025 | 1.10.9.5 | minor rtl cleanups; :bug: fix minor bug (multiple drivers on ICC nets; introduced in version 1.10.9.2) | [#1151](https://github.com/stnolting/neorv32/pull/1151) |
| 11.01.2025 | 1.10.9.4 | :warning: RTE: use a single, global trap handler table that applies to _both_ cores | [#1150](https://github.com/stnolting/neorv32/pull/1150) |
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ allows booting application code via UART, TWI or from external SPI flash
[TWI](https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi) (I²C host),
[TWD](https://stnolting.github.io/neorv32/#_two_wire_serial_device_controller_twd) (I²C device),
[ONEWIRE/1-Wire](https://stnolting.github.io/neorv32/#_one_wire_serial_interface_controller_onewire))
* general purpose IOs ([GPIO](https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio)) and
* interrupt-capable general purpose IOs ([GPIO](https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio)) and
[PWM](https://stnolting.github.io/neorv32/#_pulse_width_modulation_controller_pwm)
* smart LED interface ([NEOLED](https://stnolting.github.io/neorv32/#_smart_led_interface_neoled)) to directly control NeoPixel(TM) LEDs

Expand All @@ -177,8 +177,6 @@ allows booting application code via UART, TWI or from external SPI flash
[wrappers](https://github.com/stnolting/neorv32/blob/main/rtl/system_integration) for AXI4-Lite and Avalon-MM host interfaces
* stream link interface with independent RX and TX channels - AXI4-Stream compatible
([SLINK](https://stnolting.github.io/neorv32/#_stream_link_interface_slink))
* external interrupts controller with up to 32 channels
([XIRQ](https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq))

**Advanced**

Expand Down
3 changes: 1 addition & 2 deletions docs/datasheet/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,7 @@ rtl/core
├-neorv32_uart.vhd - Universal async. receiver/transmitter
├-neorv32_wdt.vhd - Watchdog timer
├-neorv32_xbus.vhd - External (Wishbone) bus interface gateways
├-neorv32_xip.vhd - Execute in place module
└-neorv32_xirq.vhd - External interrupt controller
└-neorv32_xip.vhd - Execute in place module
...................................
.Replacing Modules for Customization or Optimization
Expand Down
17 changes: 5 additions & 12 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,13 @@ image::neorv32_processor.png[align=center]
* _optional_ 8-bit serial data device interface (<<_serial_data_interface_controller_spi,**SDI**>>)
* _optional_ two-wire serial interface controller (<<_two_wire_serial_interface_controller_twi,**TWI**>>), compatible to the I²C standard
* _optional_ two-wire serial device controller (<<_two_wire_serial_device_controller_twd,**TWD**>>), compatible to the I²C standard
* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 64xOut, 64xIn
* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 32 inputs (interrupt capable), 32 outputs
* _optional_ 32-bit external bus interface, Wishbone b4 / AXI4-Lite compatible (<<_processor_external_bus_interface_xbus,**XBUS**>>)
* _optional_ watchdog timer (<<_watchdog_timer_wdt,**WDT**>>)
* _optional_ PWM controller with up to 16 individual channels (<<_pulse_width_modulation_controller_pwm,**PWM**>>)
* _optional_ ring-oscillator-based true random number generator (<<_true_random_number_generator_trng,**TRNG**>>)
* _optional_ custom functions subsystem for custom co-processor extensions (<<_custom_functions_subsystem_cfs,**CFS**>>)
* _optional_ NeoPixel(TM)/WS2812-compatible smart LED interface (<<_smart_led_interface_neoled,**NEOLED**>>)
* _optional_ external interrupt controller with up to 32 channels and programmable interrupt triggers (<<_external_interrupt_controller_xirq,**XIRQ**>>)
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>)
* _optional_ execute in-place module (<<_execute_in_place_module_xip,**XIP**>>)
* _optional_ 1-wire serial interface controller (<<_one_wire_serial_interface_controller_onewire,**ONEWIRE**>>), compatible to the 1-wire standard
Expand Down Expand Up @@ -123,8 +122,8 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda
| `xip_dat_i` | 1 | in | `'L'` | serial data input
| `xip_dat_o` | 1 | out | - | serial data output
5+^| **<<_general_purpose_input_and_output_port_gpio>>**
| `gpio_o` | 64 | out | - | general purpose parallel output
| `gpio_i` | 64 | in | `'L'` | general purpose parallel input
| `gpio_o` | 32 | out | - | general purpose parallel output
| `gpio_i` | 32 | in | `'L'` | general purpose parallel input (interrupt-capable)
5+^| **<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>**
| `uart0_txd_o` | 1 | out | - | serial transmitter
| `uart0_rxd_i` | 1 | in | `'L'` | serial receiver
Expand Down Expand Up @@ -167,8 +166,6 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda
| `neoled_o` | 1 | out | - | asynchronous serial data output
5+^| **<<_core_local_interruptor_clint>>**
| `mtime_time_o` | 64 | out | - | CLINT.MTIMER system time output
5+^| **<<_external_interrupt_controller_xirq>>**
| `xirq_i` | 32 | in | `'L'` | external interrupt requests
5+^| **RISC-V Machine-Mode <<_processor_interrupts>>**
| `mtime_irq_i` | 1 | in | `'L'` | machine timer interrupt (RISC-V), high-level-active; for chip-internal usage only
| `msw_irq_i` | 1 | in | `'L'` | machine software interrupt (RISC-V), high-level-active; for chip-internal usage only
Expand Down Expand Up @@ -285,11 +282,9 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| `XIP_CACHE_EN` | boolean | false | Implement XIP cache.
| `XIP_CACHE_NUM_BLOCKS` | natural | 8 | Number of blocks in XIP cache. Has to be a power of two.
| `XIP_CACHE_BLOCK_SIZE` | natural | 256 | Number of bytes per XIP cache block. Has to be a power of two, min 4.
4+^| **<<_external_interrupt_controller_xirq>>**
| `XIRQ_NUM_CH` | natural | 0 | Number of channels of the external interrupt controller. Valid values are 0..32.
4+^| **Peripheral/IO Modules**
| `IO_DISABLE_SYSINFO` | boolean | false | Disable <<_system_configuration_information_memory_sysinfo>> module; ⚠️ not recommended - for advanced users only!
| `IO_GPIO_NUM` | natural | 0 | Number of general purpose input/output pairs of the <<_general_purpose_input_and_output_port_gpio>>.
| `IO_GPIO_NUM` | natural | 0 | Number of general purpose input/output pairs of the <<_general_purpose_input_and_output_port_gpio>>, max 32.
| `IO_CLINT_EN` | boolean | false | Implement the <<_core_local_interruptor_clint>>.
| `IO_UART0_EN` | boolean | false | Implement the <<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>.
| `IO_UART0_RX_FIFO` | natural | 1 | UART0 RX FIFO depth, has to be a power of two, minimum value is 1, max 32768.
Expand Down Expand Up @@ -455,7 +450,7 @@ table (the channel number also corresponds to the according FIRQ priority: 0 = h
| 5 | <<_secondary_universal_asynchronous_receiver_and_transmitter_uart1,UART1>> | UART1 TX FIFO level interrupt
| 6 | <<_serial_peripheral_interface_controller_spi,SPI>> | SPI FIFO level interrupt
| 7 | <<_two_wire_serial_interface_controller_twi,TWI>> | TWI FIFO level interrupt
| 8 | <<_external_interrupt_controller_xirq,XIRQ>> | External interrupt controller interrupt
| 8 | <<_general_purpose_input_and_output_port_gpio,GPIO>> | GPIO input pin(s) interrupt
| 9 | <<_smart_led_interface_neoled,NEOLED>> | NEOLED TX FIFO level interrupt
| 10 | <<_direct_memory_access_controller_dma,DMA>> | DMA transfer done interrupt
| 11 | <<_serial_data_interface_controller_sdi,SDI>> | SDI FIFO level interrupt
Expand Down Expand Up @@ -826,8 +821,6 @@ include::soc_cfs.adoc[]

include::soc_neoled.adoc[]

include::soc_xirq.adoc[]

include::soc_gptmr.adoc[]

include::soc_xip.adoc[]
Expand Down
76 changes: 58 additions & 18 deletions docs/datasheet/soc_gpio.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,65 @@
| Hardware source files: | neorv32_gpio.vhd |
| Software driver files: | neorv32_gpio.c | link:https://stnolting.github.io/neorv32/sw/neorv32__gpio_8c.html[Online software reference (Doxygen)]
| | neorv32_gpio.h | link:https://stnolting.github.io/neorv32/sw/neorv32__gpio_8h.html[Online software reference (Doxygen)]
| Top entity ports: | `gpio_o` | 64-bit parallel output port
| | `gpio_i` | 64-bit parallel input port
| Configuration generics: | `IO_GPIO_NUM` | number of input/output pairs to implement (0..64)
| CPU interrupts: | none |
| Top entity ports: | `gpio_o` | 32-bit parallel output port
| | `gpio_i` | 32-bit parallel input port
| Configuration generics: | `IO_GPIO_NUM` | number of input/output pairs to implement (0..32)
| CPU interrupts: | fast IRQ channel 8 | GPIO (see <<_processor_interrupts>>)
|=======================


**Overview**

The general purpose parallel IO unit provides a simple parallel input and output port. These ports can be used
The general purpose IO unit provides simple uni-directional input and output port. These ports can be used
chip-externally (for example to drive status LEDs, connect buttons, etc.) or chip-internally to provide control
signals for other IP modules.
signals for other IP modules. The input port features programmable pin-individual level or edge interrupts
capabilities.

Data written to the `PORT_OUT` will appear on the processor's `gpio_o` port. Vice versa, the `PORT_IN` register
represents the current state of the processor's `gpio_i`.

The actual number of input/output pairs is defined by the `IO_GPIO_NUM` generic. When set to zero, the GPIO module
is excluded from synthesis and the output port `gpio_o` is tied to all-zero. If `IO_GPIO_NUM` is less than the
maximum value of 64, only the LSB-aligned bits in `gpio_o` and `gpio_i` are actually connected while the remaining
bits are tied to zero or are left unconnected, respectively.
maximum value of 32, only the LSB-aligned bits in `gpio_o` and `gpio_i` are actually connected while the remaining
bits are tied to zero or are left unconnected, respectively. This also applies to all memory-mapped interface
registers of the GPIO module (i.e. the according most-significant bits are hardwired to zero).


**Input Pin Interrupts**

Each input pin (`gpio_i`) provides an individual programmable interrupt trigger. The actual interrupt trigger
type can be configured individually for each input pin using the `IRQ_TYPE` and `IRQ_POLARITY` registers.
`IRQ_TYPE` defines the actual trigger type (level-triggered or edge-triggered), while `IRQ_POLARITY` defines
the trigger's polarity (low-level/falling-edge or high-level/rising-edge). The position of each bit in these
registers corresponds the according `gpio_i` input pin.

Each pin interrupt channel can be enabled or disabled individually using the `IRQ_ENABLE` register. Each bit
in this register corresponds to the according input pin. If the programmed trigger of a disabled input
(`IRQ_ENABLE(i) = 0`) fires, the interrupt request is entirely ignored.

.GPIO Trigger Configuration for Pin _i_
[cols="^2,^2,^2,<4"]
[options="header",grid="all"]
|=======================
| `IRQ_ENABLE(i)` | `IRQ_TYPE(i)` | `IRQ_POLARITY(i)` | Resulting trigger of `gpio_i(i)`
| `1` | `0` | `0` | low-level (`GPIO_TRIG_LEVEL_LOW`)
| `1` | `0` | `1` | high-level (`GPIO_TRIG_LEVEL_HIGH`)
| `1` | `1` | `0` | falling-edge (`GPIO_TRIG_EDGE_FALLING`)
| `1` | `1` | `1` | rising-edge (`GPIO_TRIG_EDGE_RISING`)
| `0` | `-` | `-` | interrupt disabled
|=======================

If the configured trigger of an enabled input pin (`IRQ_ENABLE(i) = 1`) fires, the according interrupt request
is buffered internally in the `IRQ_PENDING` register. When this register contains a non-zero value (i.e. any
bit becomes set) an interrupt request is sent to the CPU via FIRQ channel 8 (see <<_processor_interrupts>>).

The CPU can determine the interrupt-triggering pins by reading the `IRQ_PENDING` register. Each set bit in this
register indicates that the according input pin's interrupt trigger has fired. Then, the CPU can clear those
pending interrupt pin by setting all set bits to zero.

.Access Atomicity
[NOTE]
The GPIO modules uses two memory-mapped registers (each 32-bit) each for accessing the input and
output signals. Since the CPU can only process 32-bit "at once" updating the entire output cannot
be performed within a single clock cycle.
.GPIO Interrupts Demo Program
[TIP]
A demo program for the GPIO input interrupts can be found in `sw/example/demo_gpio`.


**Register Map**
Expand All @@ -39,9 +75,13 @@ be performed within a single clock cycle.
[cols="<2,<2,^1,^1,<6"]
[options="header",grid="rows"]
|=======================
| Address | Name [C] | Bit(s) | R/W | Function
| `0xfffc0000` | `INPUT[0]` | 31:0 | r/- | parallel input port pins 31:0
| `0xfffc0004` | `INPUT[1]` | 31:0 | r/- | parallel input port pins 63:32
| `0xfffc0008` | `OUTPUT[0]` | 31:0 | r/w | parallel output port pins 31:0
| `0xfffc000c` | `OUTPUT[1]` | 31:0 | r/w | parallel output port pins 63:32
| Address | Name [C] | Bit(s) | R/W | Function
| `0xfffc0000` | `PORT_IN` | 31:0 | r/- | Parallel input port; `PORT_IN(i)` corresponds to `gpio_i(i)`
| `0xfffc0004` | `PORT_OUT` | 31:0 | r/w | Parallel output port; `PORT_OUT(i)` corresponds to `gpio_o(i)`
| `0xfffc0008` | - | 31:0 | r/- | _reserved_, read as zero
| `0xfffc000c` | - | 31:0 | r/- | _reserved_, read as zero
| `0xfffc0010` | `IRQ_TYPE` | 31:0 | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); `IRQ_TYPE(i)` corresponds to `gpio_i(i)`
| `0xfffc0014` | `IRQ_POLARITY` | 31:0 | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); `IRQ_POLARITY(i)` corresponds to `gpio_i(i)`
| `0xfffc0018` | `IRQ_ENABLE` | 31:0 | r/w | Per-pin interrupt enable; `IRQ_ENABLE(i)` corresponds to `gpio_i(i)`
| `0xfffc001c` | `IRQ_PENDING` | 31:0 | r/c | Per-pin interrupt pending, can be cleared by writing zero to the according bit(s); `IRQ_PENDING(i)` corresponds to `gpio_i(i)`
|=======================
2 changes: 1 addition & 1 deletion docs/datasheet/soc_sysinfo.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Bit fields in this register are set to all-zero if the according memory system i
| `24` | `SYSINFO_SOC_IO_SDI` | set if SDI is implemented (via top's `IO_SDI_EN` generic)
| `25` | `SYSINFO_SOC_IO_UART1` | set if secondary UART1 is implemented (via top's `IO_UART1_EN` generic)
| `26` | `SYSINFO_SOC_IO_NEOLED` | set if NEOLED is implemented (via top's `IO_NEOLED_EN` generic)
| `27` | `SYSINFO_SOC_IO_XIRQ` | set if XIRQ is implemented (via top's `XIRQ_NUM_CH` generic)
| `27` | - |_reserved_, read as zero
| `28` | `SYSINFO_SOC_IO_GPTMR` | set if GPTMR is implemented (via top's `IO_GPTMR_EN` generic)
| `29` | `SYSINFO_SOC_IO_SLINK` | set if stream link interface is implemented (via top's `IO_SLINK_EN` generic)
| `30` | `SYSINFO_SOC_IO_ONEWIRE` | set if ONEWIRE interface is implemented (via top's `IO_ONEWIRE_EN` generic)
Expand Down
Loading

0 comments on commit 8603c0d

Please sign in to comment.