Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GPTMR timer capture #759

Merged
merged 8 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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