|
34 | 34 | #include "shared-bindings/pulseio/PulseIn.h"
|
35 | 35 | #include "tick.h"
|
36 | 36 |
|
| 37 | +#include "stm32f4xx_hal.h" |
| 38 | + |
| 39 | +#define STM32_GPIO_PORT_SIZE 16 |
| 40 | + |
| 41 | +static pulseio_pulsein_obj_t* _objs[STM32_GPIO_PORT_SIZE]; |
| 42 | + |
| 43 | +static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t* self, uint8_t num); |
| 44 | + |
| 45 | +static void pulsein_handler(uint8_t num) { |
| 46 | + // Grab the current time first. |
| 47 | + uint32_t current_us; |
| 48 | + uint64_t current_ms; |
| 49 | + current_tick(¤t_ms, ¤t_us); |
| 50 | + |
| 51 | + // current_tick gives us the remaining us until the next tick but we want the number since the last ms. |
| 52 | + current_us = 1000 - current_us; |
| 53 | + |
| 54 | + pulseio_pulsein_obj_t* self = _objs[num]; |
| 55 | + if ( !self ) return; |
| 56 | + |
| 57 | + if (self->first_edge) { |
| 58 | + // first pulse is opposite state from idle |
| 59 | + bool state = HAL_GPIO_ReadPin(pin_port(self->pin->port), pin_mask(self->pin->number)); |
| 60 | + if ( self->idle_state != state ) { |
| 61 | + self->first_edge = false; |
| 62 | + } |
| 63 | + } else { |
| 64 | + uint32_t ms_diff = current_ms - self->last_ms; |
| 65 | + uint16_t us_diff = current_us - self->last_us; |
| 66 | + uint32_t total_diff = us_diff; |
| 67 | + |
| 68 | + if (self->last_us > current_us) { |
| 69 | + total_diff = 1000 + current_us - self->last_us; |
| 70 | + if (ms_diff > 1) { |
| 71 | + total_diff += (ms_diff - 1) * 1000; |
| 72 | + } |
| 73 | + } else { |
| 74 | + total_diff += ms_diff * 1000; |
| 75 | + } |
| 76 | + uint16_t duration = 0xffff; |
| 77 | + if (total_diff < duration) { |
| 78 | + duration = total_diff; |
| 79 | + } |
| 80 | + |
| 81 | + uint16_t i = (self->start + self->len) % self->maxlen; |
| 82 | + self->buffer[i] = duration; |
| 83 | + if (self->len < self->maxlen) { |
| 84 | + self->len++; |
| 85 | + } else { |
| 86 | + self->start++; |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + self->last_ms = current_ms; |
| 91 | + self->last_us = current_us; |
| 92 | +} |
| 93 | + |
37 | 94 | void pulsein_reset(void) {
|
| 95 | + // Disable all active interrupts and clear array |
| 96 | + for (uint i = 0; i < STM32_GPIO_PORT_SIZE; i++) { |
| 97 | + if (_objs[i] != NULL) { |
| 98 | + HAL_NVIC_DisableIRQ(_objs[i]->irq); |
| 99 | + } |
| 100 | + } |
| 101 | + memset(_objs, 0, sizeof(_objs)); |
38 | 102 | }
|
39 | 103 |
|
40 | 104 | void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin,
|
41 | 105 | uint16_t maxlen, bool idle_state) {
|
42 |
| - mp_raise_NotImplementedError(translate("PulseIn not yet supported")); |
| 106 | + // STM32 has one shared EXTI for each pin number, 0-15 |
| 107 | + uint8_t p_num = pin->number; |
| 108 | + if(_objs[p_num]) { |
| 109 | + mp_raise_ValueError(translate("Pin number already reserved by EXTI")); |
| 110 | + } |
| 111 | + _objs[p_num] = self; |
| 112 | + |
| 113 | + // Allocate pulse buffer |
| 114 | + self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false); |
| 115 | + if (self->buffer == NULL) { |
| 116 | + mp_raise_msg_varg(&mp_type_MemoryError, translate("Failed to allocate RX buffer of %d bytes"), |
| 117 | + maxlen * sizeof(uint16_t)); |
| 118 | + } |
| 119 | + |
| 120 | + // Set internal variables |
| 121 | + self->pin = pin; |
| 122 | + self->maxlen = maxlen; |
| 123 | + self->idle_state = idle_state; |
| 124 | + self->start = 0; |
| 125 | + self->len = 0; |
| 126 | + self->first_edge = true; |
| 127 | + self->paused = false; |
| 128 | + self->last_us = 0; |
| 129 | + self->last_ms = 0; |
| 130 | + |
| 131 | + // EXTI pins can also be read as an input |
| 132 | + GPIO_InitTypeDef GPIO_InitStruct = {0}; |
| 133 | + GPIO_InitStruct.Pin = pin_mask(pin->number); |
| 134 | + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; |
| 135 | + GPIO_InitStruct.Pull = GPIO_NOPULL; |
| 136 | + HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); |
| 137 | + |
| 138 | + // Interrupt starts immediately |
| 139 | + assign_EXTI_Interrupt(self, pin->number); |
| 140 | + HAL_NVIC_EnableIRQ(self->irq); |
| 141 | + claim_pin(pin); |
43 | 142 | }
|
44 | 143 |
|
45 | 144 | bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) {
|
46 |
| - return true; |
| 145 | + return (self->pin == NULL); |
47 | 146 | }
|
48 | 147 |
|
49 | 148 | void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) {
|
| 149 | + if (common_hal_pulseio_pulsein_deinited(self)) { |
| 150 | + return; |
| 151 | + } |
| 152 | + HAL_NVIC_DisableIRQ(self->irq); |
| 153 | + _objs[self->pin->number] = NULL; |
| 154 | + reset_pin_number(self->pin->port, self->pin->number); |
| 155 | + self->pin = NULL; |
50 | 156 | }
|
51 | 157 |
|
52 | 158 | void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) {
|
| 159 | + HAL_NVIC_DisableIRQ(self->irq); |
| 160 | + self->paused = true; |
53 | 161 | }
|
54 | 162 |
|
55 | 163 | void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t trigger_duration) {
|
| 164 | + // Make sure we're paused. |
| 165 | + if ( !self->paused ) { |
| 166 | + common_hal_pulseio_pulsein_pause(self); |
| 167 | + } |
| 168 | + |
| 169 | + // Send the trigger pulse. |
| 170 | + if (trigger_duration > 0) { |
| 171 | + GPIO_InitTypeDef GPIO_InitStruct = {0}; |
| 172 | + GPIO_InitStruct.Pin = pin_mask(self->pin->number); |
| 173 | + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; |
| 174 | + GPIO_InitStruct.Pull = GPIO_NOPULL; |
| 175 | + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; |
| 176 | + HAL_GPIO_Init(pin_port(self->pin->port), &GPIO_InitStruct); |
| 177 | + |
| 178 | + HAL_GPIO_WritePin(pin_port(self->pin->port), pin_mask(self->pin->number), !self->idle_state); |
| 179 | + common_hal_mcu_delay_us((uint32_t)trigger_duration); |
| 180 | + HAL_GPIO_WritePin(pin_port(self->pin->port), pin_mask(self->pin->number), self->idle_state); |
| 181 | + |
| 182 | + GPIO_InitStruct.Pin = pin_mask(self->pin->number); |
| 183 | + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; |
| 184 | + GPIO_InitStruct.Pull = GPIO_NOPULL; |
| 185 | + HAL_GPIO_Init(pin_port(self->pin->port), &GPIO_InitStruct); |
| 186 | + } |
| 187 | + |
| 188 | + self->first_edge = true; |
| 189 | + self->paused = false; |
| 190 | + self->last_ms = 0; |
| 191 | + self->last_us = 0; |
| 192 | + |
| 193 | + HAL_NVIC_EnableIRQ(self->irq); |
56 | 194 | }
|
57 | 195 |
|
58 | 196 | void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) {
|
| 197 | + HAL_NVIC_DisableIRQ(self->irq); |
| 198 | + self->start = 0; |
| 199 | + self->len = 0; |
| 200 | + HAL_NVIC_EnableIRQ(self->irq); |
59 | 201 | }
|
60 | 202 |
|
61 | 203 | uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index) {
|
62 |
| - return 0; |
| 204 | + HAL_NVIC_DisableIRQ(self->irq); |
| 205 | + if (index < 0) { |
| 206 | + index += self->len; |
| 207 | + } |
| 208 | + if (index < 0 || index >= self->len) { |
| 209 | + HAL_NVIC_EnableIRQ(self->irq); |
| 210 | + mp_raise_IndexError(translate("index out of range")); |
| 211 | + } |
| 212 | + uint16_t value = self->buffer[(self->start + index) % self->maxlen]; |
| 213 | + HAL_NVIC_EnableIRQ(self->irq); |
| 214 | + return value; |
63 | 215 | }
|
64 | 216 |
|
65 | 217 | uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) {
|
66 |
| - return 0; |
| 218 | + if (self->len == 0) { |
| 219 | + mp_raise_IndexError(translate("pop from an empty PulseIn")); |
| 220 | + } |
| 221 | + HAL_NVIC_DisableIRQ(self->irq); |
| 222 | + uint16_t value = self->buffer[self->start]; |
| 223 | + self->start = (self->start + 1) % self->maxlen; |
| 224 | + self->len--; |
| 225 | + HAL_NVIC_EnableIRQ(self->irq); |
| 226 | + |
| 227 | + return value; |
67 | 228 | }
|
68 | 229 |
|
69 | 230 | uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) {
|
70 |
| - return 0; |
| 231 | + return self->maxlen; |
71 | 232 | }
|
72 | 233 |
|
73 | 234 | bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) {
|
74 |
| - return 0; |
| 235 | + return self->paused; |
75 | 236 | }
|
76 | 237 |
|
77 | 238 | uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) {
|
78 |
| - return 0; |
| 239 | + return self->len; |
| 240 | +} |
| 241 | + |
| 242 | +static void assign_EXTI_Interrupt(pulseio_pulsein_obj_t* self, uint8_t num) { |
| 243 | + if (num == 0) { |
| 244 | + self->irq = EXTI0_IRQn; |
| 245 | + } else if (num == 1) { |
| 246 | + self->irq = EXTI1_IRQn; |
| 247 | + } else if (num == 2) { |
| 248 | + self->irq = EXTI2_IRQn; |
| 249 | + } else if (num == 3) { |
| 250 | + self->irq = EXTI3_IRQn; |
| 251 | + } else if (num == 4) { |
| 252 | + self->irq = EXTI4_IRQn; |
| 253 | + } else if (num >= 5 && num <= 9 ) { |
| 254 | + self->irq = EXTI9_5_IRQn; |
| 255 | + } else if (num >= 10 && num <= 15) { |
| 256 | + self->irq = EXTI15_10_IRQn; |
| 257 | + } |
| 258 | +} |
| 259 | + |
| 260 | +void EXTI0_IRQHandler(void) |
| 261 | +{ |
| 262 | + EXTI->PR = 1 << 0; |
| 263 | + pulsein_handler(0); |
| 264 | +} |
| 265 | +void EXTI1_IRQHandler(void) |
| 266 | +{ |
| 267 | + EXTI->PR = 1 << 1; |
| 268 | + pulsein_handler(1); |
| 269 | +} |
| 270 | +void EXTI2_IRQHandler(void) |
| 271 | +{ |
| 272 | + EXTI->PR = 1 << 2; |
| 273 | + pulsein_handler(2); |
| 274 | +} |
| 275 | +void EXTI3_IRQHandler(void) |
| 276 | +{ |
| 277 | + EXTI->PR = 1 << 3; |
| 278 | + pulsein_handler(3); |
| 279 | +} |
| 280 | +void EXTI4_IRQHandler(void) |
| 281 | +{ |
| 282 | + EXTI->PR = 1 << 4; |
| 283 | + pulsein_handler(4); |
| 284 | +} |
| 285 | +void EXTI9_5_IRQHandler(void) |
| 286 | +{ |
| 287 | + uint32_t pending = EXTI->PR; |
| 288 | + if(pending & (1 << 5)) { |
| 289 | + EXTI->PR = 1 << 5; |
| 290 | + pulsein_handler(5); |
| 291 | + } else if (pending & (1 << 6)) { |
| 292 | + EXTI->PR = 1 << 6; |
| 293 | + pulsein_handler(6); |
| 294 | + } else if (pending & (1 << 7)) { |
| 295 | + EXTI->PR = 1 << 7; |
| 296 | + pulsein_handler(7); |
| 297 | + } else if (pending & (1 << 8)) { |
| 298 | + EXTI->PR = 1 << 8; |
| 299 | + pulsein_handler(8); |
| 300 | + } else if (pending & (1 << 9)) { |
| 301 | + EXTI->PR = 1 << 9; |
| 302 | + pulsein_handler(9); |
| 303 | + } |
| 304 | +} |
| 305 | + |
| 306 | +void EXTI15_10_IRQHandler(void) |
| 307 | +{ |
| 308 | + uint32_t pending = EXTI->PR; |
| 309 | + if(pending & (1 << 10)) { |
| 310 | + EXTI->PR = 1 << 10; |
| 311 | + pulsein_handler(10); |
| 312 | + } else if (pending & (1 << 11)) { |
| 313 | + EXTI->PR = 1 << 11; |
| 314 | + pulsein_handler(11); |
| 315 | + } else if (pending & (1 << 12)) { |
| 316 | + EXTI->PR = 1 << 12; |
| 317 | + pulsein_handler(12); |
| 318 | + } else if (pending & (1 << 13)) { |
| 319 | + EXTI->PR = 1 << 13; |
| 320 | + pulsein_handler(13); |
| 321 | + } else if (pending & (1 << 14)) { |
| 322 | + EXTI->PR = 1 << 14; |
| 323 | + pulsein_handler(14); |
| 324 | + } else if (pending & (1 << 15)) { |
| 325 | + EXTI->PR = 1 << 15; |
| 326 | + pulsein_handler(15); |
| 327 | + } |
79 | 328 | }
|
0 commit comments