Skip to content

Commit

Permalink
Add GPTMR timer capture (#759)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting authored Jan 6, 2024
2 parents 38f41b3 + 3871dc8 commit 80cc23c
Show file tree
Hide file tree
Showing 16 changed files with 399 additions and 120 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Link |
|:----:|:-------:|:--------|:----:|
| 06.01.2024 | 1.9.2.8 | :sparkles: add timer-capture mode to General Purpose Timer (GPTMR); :warning: remove "single-shot" mode, change control register layout | [#759](https://github.com/stnolting/neorv32/pull/759) |
| 19.12.2023 | 1.9.2.7 | minor rtl code cleanups, edits and optimization; :lock: reset `mtvec`, `mepc` and `dpc` CSRs to CPU boot address (`CPU_BOOT_ADDR` CPU generic) | [#755](https://github.com/stnolting/neorv32/pull/755) |
| 19.12.2023 | 1.9.2.6 | rework FIFO component fixing problems with inferring block RAM | [#754](https://github.com/stnolting/neorv32/pull/754) |
| 11.12.2023 | 1.9.2.5 | clean-up software framework | [#752](https://github.com/stnolting/neorv32/pull/752) |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ allows booting application code via UART or from external SPI flash
**Timers and Counters**

* 64-bit machine timer ([MTIME](https://stnolting.github.io/neorv32/#_machine_system_timer_mtime)), RISC-V spec. compatible
* 32-bit general purpose timer ([GPTMR](https://stnolting.github.io/neorv32/#_general_purpose_timer_gptmr))
* 32-bit general purpose timer ([GPTMR](https://stnolting.github.io/neorv32/#_general_purpose_timer_gptmr)) with capture input
* watchdog timer ([WDT](https://stnolting.github.io/neorv32/#_watchdog_timer_wdt))

**Input / Output**
Expand Down
4 changes: 3 additions & 1 deletion docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ image::neorv32_processor.png[align=center]
* _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 (<<_external_interrupt_controller_xirq,**XIRQ**>>)
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>)
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>) with capture input
* _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
* _optional_ autonomous direct memory access controller (<<_direct_memory_access_controller_dma,**DMA**>>)
Expand Down Expand Up @@ -150,6 +150,8 @@ Some interfaces (like the TWI and the 1-Wire bus) require tri-state drivers in t
| `cfs_out_o` | 32 | out | custom CFS output signal conduit
4+^| **<<_smart_led_interface_neoled>>**
| `neoled_o` | 1 | out | asynchronous serial data output
4+^| **<<_general_purpose_timer_gptmr>>**
| `gptmr_trig_i` | 1 | in | timer capture input
4+^| **<<_external_interrupt_controller_xirq>>**
| `xirq_i` | 32 | in | external interrupt requests
4+^| **RISC-V Machine-Mode <<_processor_interrupts>>**
Expand Down
79 changes: 53 additions & 26 deletions docs/datasheet/soc_gptmr.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,27 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_gptmr.vhd |
| Hardware source file(s): | neorv32_gptmr.vhd |
| Software driver file(s): | neorv32_gptmr.c |
| | neorv32_gptmr.h |
| Top entity port: | none |
| Configuration generics: | `IO_GPTMR_EN` | implement general purpose timer when `true`
| Top entity port: | `gptmr_trig_i` | timer capture input
| Configuration generics: | `IO_GPTMR_EN` | implement general purpose timer when `true`
| CPU interrupts: | fast IRQ channel 12 | timer interrupt (see <<_processor_interrupts>>)
|=======================


**Theory of Operation**
**Overview**

The general purpose timer module provides a simple yet universal 32-bit timer. The timer is implemented if
`IO_GPTMR_EN` top generic is set `true`. It provides a 32-bit counter register (`COUNT`) and a 32-bit threshold
register (`THRES`). An interrupt is generated whenever the value of the counter registers matches the one from
threshold register.
The general purpose timer module implements a simple yet universal 32-bit timer. It is implemented if the processor's
`IO_GPTMR_EN` top generic is set `true`. The timer provides a pre-scaled counter register that can trigger an interrupt
when reaching a programmable threshold value. Additionally, a timer-capture feature is implemented that copies the current
counter value to a dedicated register if a programmable edge occurs at the `gptmr_trig_i` input signal.

The timer is enabled by setting the `GPTMR_CTRL_EN` bit in the device's control register `CTRL`. The `COUNT`
register will start incrementing at a programmable rate, which scales the main processor clock. The
pre-scaler value is configured via the three `GPTMR_CTRL_PRSCx` control register bits:
Four interface registers are available: a control register (`CTRL`), a 32-bit counter register (`COUNT`), a 32-bit
threshold register (`THRES`) and a 32-bit read-only capture register (`CAPTURE`). The timer is globally enabled by setting the
`GPTMR_CTRL_EN` bit in the device's control register `CTRL`. When the timer is enable the `COUNT` register will start
incrementing at a programmable rate, which scales the main processor clock. The pre-scaler value is configured via the
three `GPTMR_CTRL_PRSCx` control register bits:

.GPTMR prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
Expand All @@ -33,21 +35,39 @@ pre-scaler value is configured via the three `GPTMR_CTRL_PRSCx` control register
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|=======================

The timer provides two operation modes that are configured via the `GPTMR_CTRL_MODE` control register bit:
.If `GPTMR_CTRL_MODE` is cleared (`0`) the timer operates in _single-shot mode_. As soon as `COUNT` matches
`THRES` an interrupt request is generated and the timer stops operation (i.e. it stops incrementing)
.If `GPTMR_CTRL_MODE` is set (`1`) the timer operates in _continuous mode_. When `COUNT` matches `THRES` an interrupt
request is generated and `COUNT` is automatically reset to all-zero before continuing to increment.

[NOTE]
Disabling the timer will not clear the `COUNT` register. However, it can be manually reset at any time by
writing zero to it.


**Timer Interrupt**
**Interval Timer**

Whenever the counter register `COUNT` reaches the programmable threshold value `THRES` the counter register
is reset to zero and the _timer-match_ flag `GPTMR_CTRL_TRIGM` gets set. This flag has to be cleared manually
by writing zero to it. Optionally, an interrupt can be triggered if the `GPTMR_CTRL_IRQM` bit is set.


**Timer Capture**

In addition to the the internal timer, the GPTMR provides a timer-capture feature. Whenever an edge is detected
at the `gptmr_trig_i` input signal the current `COUNT` value is copied to the read-only `CAPTURE` register and the
_capture-trigger_ flag `GPTMR_CTRL_TRIGC` gets set. This flag has to be cleared manually by writing zero to it.
Optionally, an interrupt can be triggered if the `GPTMR_CTRL_IRQC` bit is set.

The GPTMR interrupt is triggered when the timer is enabled and `COUNT` matches `THRES`. The interrupt
remains pending inside the CPU until it explicitly cleared by writing zero to the according <<_mip>> CSR bit.
The triggering edge can be a rising-edge (if `GPTMR_CTRL_RISE` is set), a falling-edge (if `GPTMR_CTRL_FALL` is
set) or even both. By default, the `gptmr_trig_i` is sampled two times at the processor clock for checking for
edges. This simple edge detection is sufficient for trigger signals that are generated by (on-chip) digital logic.

For sampling chip-external signals an optional filtering mode is available that can be enabled by the
`GPTMR_CTRL_FILTER` bit. If this bit is set, the `gptmr_trig_i` is sampled at a reduced clock speed (1/4 of the
processor clock) and the signal has to be stable for at lest 4 sample clock in order to be considered high or low.
This stabilized signal is then fed to the edge detection logic.


.Timer Interrupt
[NOTE]
Once triggered, the timer interrupt remains pending within the CPU until it explicitly cleared by writing zero
to the according <<_mip>> CSR bit.


**Register Map**
Expand All @@ -57,10 +77,17 @@ remains pending inside the CPU until it explicitly cleared by writing zero to th
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.4+<| `0xfffff100` .4+<| `CTRL` <|`0` `GPTMR_CTRL_EN` ^| r/w <| Timer enable flag
<|`3:1` `GPTMR_CTRL_PRSC2 : GPTMR_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select
<|`4` `GPTMR_CTRL_MODE` ^| r/w <| Counter mode: `0`=single-shot, `1`=continuous
<|`31:5` - ^| r/- <| _reserved_, read as zero
| `0xfffff104` | `THRES` |`31:0` | r/w | Threshold value register
| `0xfffff108` | `COUNT` |`31:0` | r/w | Counter register
.10+<| `0xfffff100` .10+<| `CTRL` <|`0` `GPTMR_CTRL_EN` ^| r/w <| Timer enable flag
<|`3:1` `GPTMR_CTRL_PRSC2 : GPTMR_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select
<|`4` `GPTMR_CTRL_IRQM` ^| r/w <| Enable interrupt on timer-match
<|`5` `GPTMR_CTRL_IRQC` ^| r/w <| Enable interrupt on capture-trigger
<|`6` `GPTMR_CTRL_RISE` ^| r/w <| Capture on rising edge
<|`7` `GPTMR_CTRL_FALL` ^| r/w <| Capture on falling edge
<|`8` `GPTMR_CTRL_FILTER` ^| r/w <| Filter capture input
<|`29:9` - ^| r/- <| _reserved_, read as zero
<|`30` `GPTMR_CTRL_TRIGM` ^| r/c <| Timer-match has fired, cleared by writing 0
<|`31` `GPTMR_CTRL_TRIGC` ^| r/c <| Capture-trigger has fired, cleared by writing 0
| `0xfffff104` | `THRES` |`31:0` | r/w | Threshold value register
| `0xfffff108` | `COUNT` |`31:0` | r/w | Counter register
| `0xfffff10C` | `CAPTURE` |`31:0` | r/- | Capture register
|=======================
Binary file modified docs/figures/neorv32_processor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 80cc23c

Please sign in to comment.