diff options
| author | Scott Shawcroft <scott@tannewt.org> | 2018-06-12 18:33:16 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-06-12 18:33:16 -0700 |
| commit | 618943d90a958d36d9b0e2206552100069b10ddb (patch) | |
| tree | ab6e182ef1e74cbb6e5fc7c1f2a5a75877d2554d | |
| parent | 144c0597e9f1a6e246ddfa5994b780d191f3221f (diff) | |
| parent | f72dcc64e6378a51045686c8b4fe820654c896ab (diff) | |
Merge pull request #926 from nickzoic/circuitpython-nickzoic-716-pulseio-esp8266
Implement pulseio.PulseIn and PulseOut for ESP8266 #716
| -rw-r--r-- | ports/esp8266/common-hal/microcontroller/Pin.c | 25 | ||||
| -rw-r--r-- | ports/esp8266/common-hal/microcontroller/Pin.h | 3 | ||||
| -rw-r--r-- | ports/esp8266/common-hal/pulseio/PulseIn.c | 124 | ||||
| -rw-r--r-- | ports/esp8266/common-hal/pulseio/PulseIn.h | 14 | ||||
| -rw-r--r-- | ports/esp8266/common-hal/pulseio/PulseOut.c | 24 | ||||
| -rw-r--r-- | ports/esp8266/common-hal/pulseio/PulseOut.h | 9 | ||||
| -rw-r--r-- | ports/esp8266/intr.c | 6 |
7 files changed, 192 insertions, 13 deletions
diff --git a/ports/esp8266/common-hal/microcontroller/Pin.c b/ports/esp8266/common-hal/microcontroller/Pin.c index 6d2af2d2e..4437d5855 100644 --- a/ports/esp8266/common-hal/microcontroller/Pin.c +++ b/ports/esp8266/common-hal/microcontroller/Pin.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include "shared-bindings/microcontroller/__init__.h" #include "common-hal/microcontroller/__init__.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Pin.h" @@ -35,6 +36,28 @@ bool adc_in_use; bool gpio16_in_use; +typedef struct { + void (*func)(void *); + void *data; +} pin_intr_handler_t; + +static pin_intr_handler_t _pin_intr_handlers[GPIO_PIN_COUNT]; + +void microcontroller_pin_call_intr_handlers(uint32_t status) { + status &= (1 << GPIO_PIN_COUNT) - 1; + for (int p = 0; status; ++p, status >>= 1) { + if ((status & 1) && _pin_intr_handlers[p].func) { + _pin_intr_handlers[p].func(_pin_intr_handlers[p].data); + } + } +} + +void microcontroller_pin_register_intr_handler(uint8_t gpio_number, void (*func)(void *), void *data) { + common_hal_mcu_disable_interrupts(); + _pin_intr_handlers[gpio_number] = (pin_intr_handler_t){ func, data }; + common_hal_mcu_enable_interrupts(); +} + bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) { if (pin == &pin_TOUT) { return !adc_in_use; @@ -92,4 +115,4 @@ void reset_pins(void) { adc_in_use = false; gpio16_in_use = false; -}
\ No newline at end of file +} diff --git a/ports/esp8266/common-hal/microcontroller/Pin.h b/ports/esp8266/common-hal/microcontroller/Pin.h index 3aa290bbd..b00a4a817 100644 --- a/ports/esp8266/common-hal/microcontroller/Pin.h +++ b/ports/esp8266/common-hal/microcontroller/Pin.h @@ -45,4 +45,7 @@ void claim_pin(const mcu_pin_obj_t* pin); void reset_pin(const mcu_pin_obj_t* pin); void reset_pins(void); +void microcontroller_pin_register_intr_handler(uint8_t gpio_number, void (*func)(void *), void *data); +void microcontroller_pin_call_intr_handlers(uint32_t status); + #endif // MICROPY_INCLUDED_ESP8266_COMMON_HAL_MICROCONTROLLER_PIN_H diff --git a/ports/esp8266/common-hal/pulseio/PulseIn.c b/ports/esp8266/common-hal/pulseio/PulseIn.c index 5930daab2..9720eaad5 100644 --- a/ports/esp8266/common-hal/pulseio/PulseIn.c +++ b/ports/esp8266/common-hal/pulseio/PulseIn.c @@ -26,51 +26,161 @@ #include <stdint.h> +#include <user_interface.h> +#include <eagle_soc.h> +#include "esp_mphal.h" + #include "mpconfigport.h" #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/pulseio/PulseIn.h" +#include "common-hal/microcontroller/__init__.h" + +static void pulsein_set_interrupt(pulseio_pulsein_obj_t *self, bool rising, bool falling) { + ETS_GPIO_INTR_DISABLE(); + // Set interrupt mode + GPIO_REG_WRITE( + GPIO_PIN_ADDR(self->pin->gpio_number), + (GPIO_REG_READ(GPIO_PIN_ADDR(self->pin->gpio_number) & ~GPIO_PIN_INT_TYPE_MASK)) | + GPIO_PIN_INT_TYPE_SET( + (rising ? GPIO_PIN_INTR_POSEDGE : 0) | (falling ? GPIO_PIN_INTR_NEGEDGE : 0) + ) + ); + // Clear interrupt status + GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << self->pin->gpio_number); + ETS_GPIO_INTR_ENABLE(); +} + +void pulseio_pulsein_interrupt_handler(void *data) { + pulseio_pulsein_obj_t *self = data; + uint32_t time_us = system_get_time(); + if (self->first_edge) { + self->first_edge = false; + pulsein_set_interrupt(self, true, true); + } else { + uint16_t elapsed_us = (uint16_t)(time_us - self->last_us); + uint16_t i = (self->start + self->len) % self->maxlen; + self->buffer[i] = elapsed_us; + if (self->len < self->maxlen) { + self->len++; + } else { + self->start++; + } + } + self->last_us = time_us; +} void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t* self, const mcu_pin_obj_t* pin, uint16_t maxlen, bool idle_state) { - mp_raise_NotImplementedError(""); + if (pin->gpio_number == NO_GPIO || pin->gpio_function == SPECIAL_CASE) { + mp_raise_msg_varg(&mp_type_ValueError, "No PulseIn support for %q", pin->name ); + } + PIN_FUNC_SELECT(pin->peripheral, pin->gpio_function); + PIN_PULLUP_DIS(pin->peripheral); + self->pin = pin; + + self->buffer = (uint16_t *) m_malloc(maxlen * sizeof(uint16_t), false); + if (self->buffer == NULL) { + mp_raise_msg_varg(&mp_type_MemoryError, "Failed to allocate RX buffer of %d bytes", maxlen * sizeof(uint16_t)); + } + + self->maxlen = maxlen; + self->idle_state = idle_state; + self->start = 0; + self->len = 0; + self->first_edge = true; + self->last_us = 0; + self->paused = false; + + microcontroller_pin_register_intr_handler(self->pin->gpio_number, + pulseio_pulsein_interrupt_handler, (void *)self); + pulsein_set_interrupt(self, !idle_state, idle_state); } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t* self) { - return true; + return self->buffer == NULL; } void common_hal_pulseio_pulsein_deinit(pulseio_pulsein_obj_t* self) { + pulsein_set_interrupt(self, false, false); + microcontroller_pin_register_intr_handler(self->pin->gpio_number, NULL, NULL); + PIN_FUNC_SELECT(self->pin->peripheral, 0); + m_free(self->buffer); + self->buffer = NULL; } void common_hal_pulseio_pulsein_pause(pulseio_pulsein_obj_t* self) { + pulsein_set_interrupt(self, false, false); + self->paused = true; } void common_hal_pulseio_pulsein_resume(pulseio_pulsein_obj_t* self, uint16_t trigger_duration) { + // Make sure we're paused. + common_hal_pulseio_pulsein_pause(self); + + // Send the trigger pulse. + if (trigger_duration > 0) { + uint32_t mask = 1 << self->pin->gpio_number; + // switch pin to an output with state opposite idle state + gpio_output_set(self->idle_state ? 0 : mask, self->idle_state ? mask : 0, 0, 0); + gpio_output_set(0, 0, mask, 0); + common_hal_mcu_delay_us((uint32_t)trigger_duration); + // switch pin back to an open input + gpio_output_set(0, 0, 0, mask); + } + + common_hal_mcu_disable_interrupts(); + self->first_edge = true; + pulsein_set_interrupt(self, !self->idle_state, self->idle_state); + common_hal_mcu_enable_interrupts(); + self->paused = false; } void common_hal_pulseio_pulsein_clear(pulseio_pulsein_obj_t* self) { + common_hal_mcu_disable_interrupts(); + self->start = 0; + self->len = 0; + common_hal_mcu_enable_interrupts(); } uint16_t common_hal_pulseio_pulsein_popleft(pulseio_pulsein_obj_t* self) { - return 0; + if (self->len == 0) { + mp_raise_IndexError("pop from an empty PulseIn"); + } + common_hal_mcu_disable_interrupts(); + uint16_t value = self->buffer[self->start]; + self->start = (self->start + 1) % self->maxlen; + self->len--; + common_hal_mcu_enable_interrupts(); + + return value; } uint16_t common_hal_pulseio_pulsein_get_maxlen(pulseio_pulsein_obj_t* self) { - return 0; + return self->maxlen; } bool common_hal_pulseio_pulsein_get_paused(pulseio_pulsein_obj_t* self) { - return false; + return self->paused; } uint16_t common_hal_pulseio_pulsein_get_len(pulseio_pulsein_obj_t* self) { - return 0; + return self->len; } uint16_t common_hal_pulseio_pulsein_get_item(pulseio_pulsein_obj_t* self, int16_t index) { - return 0; + common_hal_mcu_disable_interrupts(); + if (index < 0) { + index += self->len; + } + if (index < 0 || index >= self->len) { + common_hal_mcu_enable_interrupts(); + mp_raise_IndexError("index out of range"); + } + uint16_t value = self->buffer[(self->start + index) % self->maxlen]; + common_hal_mcu_enable_interrupts(); + return value; } diff --git a/ports/esp8266/common-hal/pulseio/PulseIn.h b/ports/esp8266/common-hal/pulseio/PulseIn.h index 437299f44..6319280e8 100644 --- a/ports/esp8266/common-hal/pulseio/PulseIn.h +++ b/ports/esp8266/common-hal/pulseio/PulseIn.h @@ -28,11 +28,23 @@ #define MICROPY_INCLUDED_ESP8266_COMMON_HAL_PULSEIO_PULSEIN_H #include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" typedef struct { mp_obj_base_t base; + const mcu_pin_obj_t *pin; + uint16_t *buffer; + uint16_t maxlen; + bool idle_state; + bool paused; + volatile uint16_t start; + volatile uint16_t len; + volatile bool first_edge; + volatile uint32_t last_us; } pulseio_pulsein_obj_t; -void pwmout_reset(void); +void pulsein_reset(void); + +void pulsein_interrupt_handler(uint32_t); #endif // MICROPY_INCLUDED_ESP8266_COMMON_HAL_PULSEIO_PULSEIN_H diff --git a/ports/esp8266/common-hal/pulseio/PulseOut.c b/ports/esp8266/common-hal/pulseio/PulseOut.c index db2f7cbd9..c5e63013d 100644 --- a/ports/esp8266/common-hal/pulseio/PulseOut.c +++ b/ports/esp8266/common-hal/pulseio/PulseOut.c @@ -24,23 +24,41 @@ * THE SOFTWARE. */ +#include "common-hal/pulseio/PulseOut.h" #include <stdint.h> +#include <pwm.h> + +#include "ets_alt_task.h" +#include "py/obj.h" #include "py/runtime.h" +#include "mpconfigport.h" #include "shared-bindings/pulseio/PulseOut.h" +void pulseout_set(pulseio_pulseout_obj_t *self, bool state) { + PIN_FUNC_SELECT(self->pin->peripheral, state ? self->pin->gpio_function : 0); +} + void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, const pulseio_pwmout_obj_t* carrier) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No hardware support for PulseOut.")); + self->pin = carrier->pin; } bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { - return true; + return self->pin == NULL; } void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { + self->pin = NULL; + pulseout_set(self, true); } -void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pulses, uint16_t length) { +void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, + uint16_t* pulses, uint16_t length) { + for (uint16_t i = 0; i<length; i++) { + pulseout_set(self, i % 2 == 0); + ets_delay_us(pulses[i]); + } + pulseout_set(self, false); } diff --git a/ports/esp8266/common-hal/pulseio/PulseOut.h b/ports/esp8266/common-hal/pulseio/PulseOut.h index f4b8b910f..c4bfdbcad 100644 --- a/ports/esp8266/common-hal/pulseio/PulseOut.h +++ b/ports/esp8266/common-hal/pulseio/PulseOut.h @@ -27,12 +27,19 @@ #ifndef MICROPY_INCLUDED_ESP8266_COMMON_HAL_PULSEIO_PULSEOUT_H #define MICROPY_INCLUDED_ESP8266_COMMON_HAL_PULSEIO_PULSEOUT_H +#include "common-hal/microcontroller/Pin.h" + +#include "esp_mphal.h" + #include "py/obj.h" typedef struct { mp_obj_base_t base; + os_timer_t timer; + const mcu_pin_obj_t *pin; } pulseio_pulseout_obj_t; -void pwmout_reset(void); +void pulseout_reset(void); +void pulseout_interrupt_handler(void *); #endif // MICROPY_INCLUDED_ESP8266_COMMON_HAL_PULSEIO_PULSEOUT_H diff --git a/ports/esp8266/intr.c b/ports/esp8266/intr.c index 456d6cb04..806417174 100644 --- a/ports/esp8266/intr.c +++ b/ports/esp8266/intr.c @@ -28,10 +28,16 @@ #include "ets_alt_task.h" #include "modmachine.h" +#include "common-hal/pulseio/PulseIn.h" // this is in a separate file so it can go in iRAM void pin_intr_handler_iram(void *arg) { uint32_t status = GPIO_REG_READ(GPIO_STATUS_ADDRESS); GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, status); + + // machine.Pin handlers pin_intr_handler(status); + + // microcontroller.Pin handlers + microcontroller_pin_call_intr_handlers(status); } |
