2929#include <stdint.h>
3030#include <string.h>
3131
32+ #include "nrf/timers.h"
3233#include "py/mpconfig.h"
3334#include "py/gc.h"
3435#include "py/runtime.h"
4142// obj array to map pin -> self since nrfx hide the mapping
4243static pulseio_pulsein_obj_t * _objs [GPIOTE_CH_NUM ];
4344
45+ // A single timer is shared amongst all PulseIn objects as a common high speed clock reference.
46+ static uint8_t refcount = 0 ;
47+ static nrfx_timer_t * timer = NULL ;
48+
49+ static uint32_t overflow_count = 0 ;
50+
51+ static void timer_overflow_event_handler (nrf_timer_event_t event_type , void * p_context ) {
52+ if (event_type != NRF_TIMER_EVENT_COMPARE0 ) {
53+ // Other event.
54+ return ;
55+ }
56+ overflow_count ++ ;
57+ }
58+
4459// return index of the object in array
4560static int _find_pulsein_obj (pulseio_pulsein_obj_t * obj ) {
4661 for (size_t i = 0 ; i < NRFX_ARRAY_SIZE (_objs ); i ++ ) {
@@ -54,13 +69,8 @@ static int _find_pulsein_obj(pulseio_pulsein_obj_t* obj) {
5469
5570static void _pulsein_handler (nrfx_gpiote_pin_t pin , nrf_gpiote_polarity_t action ) {
5671 // Grab the current time first.
57- uint32_t current_us = 0 ;
58- uint64_t current_ms = 0 ;
59- // FIXME! We need a higher resolution clock to measure against.
60- //current_tick(¤t_ms, ¤t_us);
61-
62- // current_tick gives us the remaining us until the next tick but we want the number since the last ms.
63- current_us = 1000 - current_us ;
72+ uint32_t current_overflow = overflow_count ;
73+ uint32_t current_count = nrfx_timer_capture (timer , 1 );
6474
6575 pulseio_pulsein_obj_t * self = NULL ;
6676 for (size_t i = 0 ; i < NRFX_ARRAY_SIZE (_objs ); i ++ ) {
@@ -78,18 +88,16 @@ static void _pulsein_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
7888 self -> first_edge = false;
7989 }
8090 }else {
81- uint32_t ms_diff = current_ms - self -> last_ms ;
82- uint16_t us_diff = current_us - self -> last_us ;
83- uint32_t total_diff = us_diff ;
84-
85- if (self -> last_us > current_us ) {
86- total_diff = 1000 + current_us - self -> last_us ;
87- if (ms_diff > 1 ) {
88- total_diff += (ms_diff - 1 ) * 1000 ;
89- }
90- } else {
91- total_diff += ms_diff * 1000 ;
91+ // Wrapped around a number of times.
92+ uint32_t total_diff = 0xffff ;
93+ // Wrapped around once so
94+ if (self -> last_overflow == current_overflow - 1 ) {
95+ total_diff = current_count + (0xffffffff - self -> last_count );
96+ } else if (self -> last_overflow == current_overflow ) {
97+ total_diff = current_count - self -> last_count ;
9298 }
99+
100+ // Cap duration at 16 bits.
93101 uint16_t duration = 0xffff ;
94102 if (total_diff < duration ) {
95103 duration = total_diff ;
@@ -104,8 +112,8 @@ static void _pulsein_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action
104112 }
105113 }
106114
107- self -> last_ms = current_ms ;
108- self -> last_us = current_us ;
115+ self -> last_overflow = current_overflow ;
116+ self -> last_count = current_count ;
109117}
110118
111119void pulsein_reset (void ) {
@@ -114,6 +122,11 @@ void pulsein_reset(void) {
114122 }
115123 nrfx_gpiote_init (NRFX_GPIOTE_CONFIG_IRQ_PRIORITY );
116124
125+ if (timer != NULL ) {
126+ nrf_peripherals_free_timer (timer );
127+ }
128+ refcount = 0 ;
129+
117130 memset (_objs , 0 , sizeof (_objs ));
118131}
119132
@@ -129,15 +142,36 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu
129142 mp_raise_msg_varg (& mp_type_MemoryError , translate ("Failed to allocate RX buffer of %d bytes" ), maxlen * sizeof (uint16_t ));
130143 }
131144
145+ if (refcount == 0 ) {
146+ timer = nrf_peripherals_allocate_timer ();
147+ if (timer == NULL ) {
148+ mp_raise_RuntimeError (translate ("All timers in use" ));
149+ }
150+ overflow_count = 0 ;
151+
152+ nrfx_timer_config_t timer_config = {
153+ // PulseIn durations are in microseconds, so this is convenient.
154+ .frequency = NRF_TIMER_FREQ_1MHz ,
155+ .mode = NRF_TIMER_MODE_TIMER ,
156+ .bit_width = NRF_TIMER_BIT_WIDTH_32 ,
157+ .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY ,
158+ };
159+
160+ nrfx_timer_init (timer , & timer_config , & timer_overflow_event_handler );
161+ // Interrupt on overflow so we can track when it rolls over.
162+ nrfx_timer_compare (timer , 0 , 0 , true);
163+ }
164+ refcount ++ ;
165+
132166 self -> pin = pin -> number ;
133167 self -> maxlen = maxlen ;
134168 self -> idle_state = idle_state ;
135169 self -> start = 0 ;
136170 self -> len = 0 ;
137171 self -> first_edge = true;
138172 self -> paused = false;
139- self -> last_us = 0 ;
140- self -> last_ms = 0 ;
173+ self -> last_overflow = 0 ;
174+ self -> last_count = 0 ;
141175
142176 claim_pin (pin );
143177
@@ -173,6 +207,11 @@ void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
173207
174208 reset_pin_number (self -> pin );
175209 self -> pin = NO_PIN ;
210+
211+ refcount -- ;
212+ if (refcount == 0 ) {
213+ nrf_peripherals_free_timer (timer );
214+ }
176215}
177216
178217void common_hal_pulseio_pulsein_pause (pulseio_pulsein_obj_t * self ) {
@@ -207,8 +246,8 @@ void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t tri
207246
208247 self -> first_edge = true;
209248 self -> paused = false;
210- self -> last_ms = 0 ;
211- self -> last_us = 0 ;
249+ self -> last_overflow = 0 ;
250+ self -> last_count = 0 ;
212251
213252 nrfx_gpiote_in_event_enable (self -> pin , true);
214253}
0 commit comments