Skip to content

Commit 88fcc19

Browse files
committed
Add PulseIn
1 parent f951298 commit 88fcc19

File tree

5 files changed

+184
-9
lines changed

5 files changed

+184
-9
lines changed

ports/esp32s2/background.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,17 @@
3535
#include "shared-module/displayio/__init__.h"
3636
#endif
3737

38+
#if CIRCUITPY_PULSEIO
39+
#include "common-hal/pulseio/PulseIn.h"
40+
#endif
41+
3842

3943
void port_background_task(void) {
4044
// Zero delay in case FreeRTOS wants to switch to something else.
4145
vTaskDelay(0);
46+
#if CIRCUITPY_PULSEIO
47+
pulsein_background();
48+
#endif
4249
}
4350

4451
void port_start_background_task(void) {}

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

Lines changed: 168 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,49 +27,208 @@
2727
#include "common-hal/pulseio/PulseIn.h"
2828
#include "py/runtime.h"
2929

30-
// STATIC void pulsein_handler(uint8_t num) {
31-
// }
30+
STATIC uint8_t refcount = 0;
31+
STATIC pulseio_pulsein_obj_t * handles[RMT_CHANNEL_MAX];
32+
33+
// Requires rmt.c void esp32s2_peripherals_reset_all(void) to reset
34+
35+
STATIC void update_internal_buffer(pulseio_pulsein_obj_t* self) {
36+
//mp_printf(&mp_plat_print, "Update internal Buffer\n");
37+
uint32_t length = 0;
38+
rmt_item32_t *items = (rmt_item32_t *) xRingbufferReceive(self->buf_handle, &length, 0);
39+
if (items) {
40+
length /= 4;
41+
//mp_printf(&mp_plat_print, "Length%d\n",length);
42+
// TODO: If the size of the recieve is larger than the buffer, reset it?
43+
44+
for (size_t i=0; i < length; i++) {
45+
//mp_printf(&mp_plat_print, "Item d0:%d, l0:%d, d1:%d, l1:%d\n",(items[i].duration0 * 3),
46+
// items[i].level0,(items[i].duration1 * 3),items[i].level1);
47+
uint16_t pos = (self->start + self->len) % self->maxlen;
48+
self->buffer[pos] = items[i].duration0 * 3;
49+
// Check if second item exists before incrementing
50+
if (items[i].duration1) {
51+
self->buffer[pos+1] = items[i].duration1 * 3;
52+
if (self->len < (self->maxlen - 1)) {
53+
self->len += 2;
54+
} else {
55+
self->start += 2;
56+
}
57+
} else {
58+
if (self->len < self->maxlen) {
59+
self->len++;
60+
} else {
61+
self->start++;
62+
}
63+
}
64+
}
65+
vRingbufferReturnItem(self->buf_handle, (void *) items);
66+
}
67+
}
68+
69+
// We can't access the RMT interrupt, so we need a global service to prevent
70+
// the ringbuffer from overflowing and crashing the peripheral
71+
void pulsein_background(void) {
72+
//mp_printf(&mp_plat_print, "BG Task!\n");
73+
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
74+
if (handles[i]) {
75+
//mp_printf(&mp_plat_print, "Located viable handle:%d\n",i);
76+
update_internal_buffer(handles[i]);
77+
UBaseType_t items_waiting;
78+
vRingbufferGetInfo(handles[i]->buf_handle, NULL, NULL, NULL, NULL, &items_waiting);
79+
//mp_printf(&mp_plat_print, "items waiting:%d\n",items_waiting);
80+
// if (items_waiting > handles[i]->maxlen) {
81+
// mp_printf(&mp_plat_print, "Overage!\n");
82+
// mp_printf(&mp_plat_print, "Items waiting detected:%d\n", items_waiting);
83+
// update_internal_buffer(handles[i]);
84+
// }
85+
}
86+
}
87+
}
3288

3389
void pulsein_reset(void) {
90+
mp_printf(&mp_plat_print, "Pulsein Reset called\n");
91+
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
92+
handles[i] = NULL;
93+
}
94+
supervisor_disable_tick();
95+
refcount = 0;
3496
}
3597

3698
void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin,
3799
uint16_t maxlen, bool idle_state) {
38-
mp_raise_NotImplementedError(translate("PulseIn not supported on this chip"));
100+
self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false);
101+
if (self->buffer == NULL) {
102+
mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), maxlen * sizeof(uint16_t));
103+
}
104+
self->pin = pin;
105+
self->maxlen = maxlen;
106+
// self->idle_state = idle_state;
107+
self->start = 0;
108+
self->len = 0;
109+
// self->first_edge = true;
110+
self->paused = false;
111+
// self->last_overflow = 0;
112+
// self->last_count = 0;
113+
114+
rmt_channel_t channel = esp32s2_peripherals_find_and_reserve_rmt();
115+
mp_printf(&mp_plat_print, "Selected Channel:%d!\n",channel);
116+
117+
// Configure Channel
118+
rmt_config_t config = RMT_DEFAULT_CONFIG_RX(pin->number, channel);
119+
config.rx_config.filter_en = true;
120+
config.rx_config.idle_threshold = 30000;
121+
config.clk_div = 240;
122+
123+
rmt_config(&config);
124+
size_t len = 1000; //TODO: pick a reasonable number for this?
125+
// size_t len = maxlen * 4;
126+
rmt_driver_install(channel, len, 0);
127+
128+
self->channel = channel;
129+
130+
// Store handle for background updates
131+
handles[channel] = self;
132+
133+
rmt_get_ringbuf_handle(channel, &(self->buf_handle));
134+
rmt_rx_start(channel, true);
135+
136+
supervisor_enable_tick();
137+
refcount++;
39138
}
40139

41140
bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) {
42-
return false;
141+
return handles[self->channel] ? true : false;
43142
}
44143

45144
void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
145+
handles[self->channel] = NULL;
146+
esp32s2_peripherals_free_rmt(self->channel);
147+
reset_pin_number(self->pin);
148+
refcount--;
149+
if (refcount == 0) {
150+
supervisor_disable_tick();
151+
}
46152
}
47153

48154
void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) {
155+
self->paused = true;
156+
rmt_rx_stop();
49157
}
50158

51159
void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t trigger_duration) {
160+
// Make sure we're paused.
161+
if ( !self->paused ) {
162+
common_hal_pulseio_pulsein_pause(self);
163+
}
164+
165+
self->paused = false;
166+
rmt_rx_start();
52167
}
53168

54169
void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) {
170+
self->start = 0;
171+
self->len = 0;
55172
}
56173

57174
uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index) {
58-
return false;
175+
//mp_printf(&mp_plat_print, "Call GetItem\n");
176+
update_internal_buffer(self);
177+
if (index < 0) {
178+
index += self->len;
179+
}
180+
if (index < 0 || index >= self->len) {
181+
mp_raise_IndexError(translate("index out of range"));
182+
}
183+
uint16_t value = self->buffer[(self->start + index) % self->maxlen];
184+
return value;
59185
}
60186

61187
uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) {
62-
return false;
188+
mp_printf(&mp_plat_print, "Call PopLeft\n");
189+
update_internal_buffer(self);
190+
191+
if (self->len == 0) {
192+
mp_raise_IndexError(translate("pop from an empty PulseIn"));
193+
}
194+
195+
uint16_t value = self->buffer[self->start];
196+
self->start = (self->start + 1) % self->maxlen;
197+
self->len--;
198+
199+
return value;
200+
201+
202+
// uint32_t length = 0;
203+
// rmt_item32_t *items = (rmt_item32_t *) xRingbufferReceive(self->buf_handle, &length, 10);
204+
// mp_printf(&mp_plat_print, "Length%d\n",length);
205+
// if (items) {
206+
// length /= 4;
207+
// mp_printf(&mp_plat_print, "Length%d\n",length);
208+
// for (size_t i=0; i < length; i++) {
209+
// mp_printf(&mp_plat_print, "Item d0:%d, l0:%d, d1:%d, l1:%d\n",(items[i].duration0 * 3),
210+
// items[i].level0,(items[i].duration1 * 3),items[i].level1);
211+
// }
212+
// vRingbufferReturnItem(self->buf_handle, (void *) items);
213+
// }
214+
// // while(items) {
215+
// // mp_printf(&mp_plat_print, "Length%d",length);
216+
// // mp_printf(&mp_plat_print, "Item val0:%d, val1:%d, val:%d",items->duration0,
217+
// // items->duration1,items->val);
218+
// // vRingbufferReturnItem(self->buf_handle, (void *) items);
219+
// // items = (rmt_item32_t *) xRingbufferReceive(self->buf_handle, &length, 1);
220+
// // }
221+
// return items ? items[0].duration0 : false;
63222
}
64223

65224
uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) {
66-
return false;
225+
return self->maxlen;
67226
}
68227

69228
bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
70-
return false;
229+
return self->paused;
71230
}
72231

73232
uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
74-
return false;
233+
return self->len;
75234
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,18 @@
3030
#include "common-hal/microcontroller/Pin.h"
3131

3232
#include "py/obj.h"
33+
#include "driver/rmt.h"
34+
#include "rmt.h"
3335

3436
typedef struct {
3537
mp_obj_base_t base;
3638

3739
const mcu_pin_obj_t* pin;
40+
rmt_channel_t channel;
3841
bool idle_state;
3942
bool paused;
43+
44+
RingbufHandle_t buf_handle;
4045
volatile bool first_edge;
4146

4247
uint16_t* buffer;
@@ -49,5 +54,6 @@ typedef struct {
4954
} pulseio_pulsein_obj_t;
5055

5156
void pulsein_reset(void);
57+
void pulsein_background(void);
5258

5359
#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PULSEIN_H

ports/esp32s2/peripherals/rmt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
bool rmt_reserved_channels[RMT_CHANNEL_MAX];
3131

3232
void esp32s2_peripherals_rmt_reset(void) {
33+
mp_printf(&mp_plat_print, "RMT Reset called\n");
3334
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
3435
if (rmt_reserved_channels[i]) {
3536
esp32s2_peripherals_free_rmt(i);

ports/esp32s2/supervisor/port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "common-hal/busio/SPI.h"
4040
#include "common-hal/busio/UART.h"
4141
#include "common-hal/pulseio/PWMOut.h"
42+
#include "common-hal/pulseio/PulseIn.h"
4243
#include "supervisor/memory.h"
4344
#include "supervisor/shared/tick.h"
4445

@@ -70,6 +71,7 @@ void reset_port(void) {
7071
#if CIRCUITPY_PULSEIO
7172
esp32s2_peripherals_rmt_reset();
7273
pwmout_reset();
74+
pulsein_reset();
7375
#endif
7476
#if CIRCUITPY_BUSIO
7577
i2c_reset();

0 commit comments

Comments
 (0)