Skip to content

Commit 00d5f63

Browse files
committed
Hopefully fix PulseIn
1 parent ed5cdd7 commit 00d5f63

2 files changed

Lines changed: 65 additions & 26 deletions

File tree

ports/nrf/common-hal/pulseio/PulseIn.c

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
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"
@@ -41,6 +42,20 @@
4142
// obj array to map pin -> self since nrfx hide the mapping
4243
static 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
4560
static 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

5570
static 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(&current_ms, &current_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

111119
void 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

178217
void 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
}

ports/nrf/common-hal/pulseio/PulseIn.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ typedef struct {
4444

4545
volatile uint16_t start;
4646
volatile uint16_t len;
47-
volatile uint16_t last_us;
48-
volatile uint64_t last_ms;
47+
volatile size_t last_overflow;
48+
volatile size_t last_count;
4949
} pulseio_pulsein_obj_t;
5050

5151
void pulsein_reset(void);

0 commit comments

Comments
 (0)