Add PulseOut

This commit is contained in:
Lucian Copeland 2020-08-04 10:59:05 -04:00
parent 98469322b7
commit f9512983ff
8 changed files with 87 additions and 34 deletions

View File

@ -29,32 +29,52 @@
#include "shared-bindings/pulseio/PWMOut.h" #include "shared-bindings/pulseio/PWMOut.h"
#include "py/runtime.h" #include "py/runtime.h"
// STATIC void turn_on(pulseio_pulseout_obj_t *pulseout) { // Requires rmt.c void esp32s2_peripherals_reset_all(void) to reset
// }
// STATIC void turn_off(pulseio_pulseout_obj_t *pulseout) {
// }
// STATIC void start_timer(void) {
// }
// STATIC void pulseout_event_handler(void) {
// }
void pulseout_reset() {
}
void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
const pulseio_pwmout_obj_t* carrier) { const mcu_pin_obj_t* pin,
mp_raise_NotImplementedError(translate("PulseOut not supported on this chip")); uint32_t frequency) {
rmt_channel_t channel = esp32s2_peripherals_find_and_reserve_rmt();
// Configure Channel
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin->number, channel);
config.tx_config.carrier_en = true;
config.tx_config.carrier_duty_percent = 50;
config.tx_config.carrier_freq_hz = frequency;
config.clk_div = 80;
rmt_config(&config);
rmt_driver_install(channel, 0, 0);
self->channel = channel;
} }
bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) { bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self) {
return false; return (self->channel == RMT_CHANNEL_MAX);
} }
void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) { void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
esp32s2_peripherals_free_rmt(self->channel);
self->channel = RMT_CHANNEL_MAX;
} }
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) {
rmt_item32_t items[length];
// Circuitpython allows 16 bit pulse values, while ESP32 only allows 15 bits
// Thus, we use entire items for one pulse, rather than switching inside each item
for (size_t i = 0; i < length; i++) {
// Setting the RMT duration to 0 has undefined behavior, so avoid that pre-emptively.
if (pulses[i] == 0) {
pulses[i] = 1;
}
uint32_t level = (i % 2) ? 0 : 1;
const rmt_item32_t item = {{{ (pulses[i] & 0x8000 ? 0x7FFF : 1), level, (pulses[i] & 0x7FFF), level}}};
items[i] = item;
}
rmt_write_items(self->channel, items, length, true);
rmt_wait_tx_done(self->channel, pdMS_TO_TICKS(100));
} }

View File

@ -29,14 +29,14 @@
#include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Pin.h"
#include "common-hal/pulseio/PWMOut.h" #include "common-hal/pulseio/PWMOut.h"
#include "driver/rmt.h"
#include "rmt.h"
#include "py/obj.h" #include "py/obj.h"
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
pulseio_pwmout_obj_t *pwmout; rmt_channel_t channel;
} pulseio_pulseout_obj_t; } pulseio_pulseout_obj_t;
void pulseout_reset(void);
#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PULSEOUT_H #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PULSEOUT_H

View File

@ -28,19 +28,20 @@
#ifndef ESP32S2_MPCONFIGPORT_H__ #ifndef ESP32S2_MPCONFIGPORT_H__
#define ESP32S2_MPCONFIGPORT_H__ #define ESP32S2_MPCONFIGPORT_H__
#define CIRCUITPY_INTERNAL_NVM_SIZE (0) #define CIRCUITPY_INTERNAL_NVM_SIZE (0)
#define MICROPY_NLR_THUMB (0) #define MICROPY_NLR_THUMB (0)
#define MICROPY_PY_UJSON (0) #define MICROPY_PY_UJSON (0)
#define MICROPY_USE_INTERNAL_PRINTF (0) #define MICROPY_USE_INTERNAL_PRINTF (0)
#include "py/circuitpy_mpconfig.h" #include "py/circuitpy_mpconfig.h"
#define CPY_PULSEOUT_USES_DIGITALIO (1)
#define MICROPY_PORT_ROOT_POINTERS \ #define MICROPY_PORT_ROOT_POINTERS \
CIRCUITPY_COMMON_ROOT_POINTERS CIRCUITPY_COMMON_ROOT_POINTERS
#define MICROPY_NLR_SETJMP (1) #define MICROPY_NLR_SETJMP (1)
#define CIRCUITPY_DEFAULT_STACK_SIZE 0x6000 #define CIRCUITPY_DEFAULT_STACK_SIZE (0x6000)
#endif // __INCLUDED_ESP32S2_MPCONFIGPORT_H #endif // __INCLUDED_ESP32S2_MPCONFIGPORT_H

View File

@ -29,6 +29,14 @@
bool rmt_reserved_channels[RMT_CHANNEL_MAX]; bool rmt_reserved_channels[RMT_CHANNEL_MAX];
void esp32s2_peripherals_rmt_reset(void) {
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
if (rmt_reserved_channels[i]) {
esp32s2_peripherals_free_rmt(i);
}
}
}
rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void) { rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void) {
for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) { for (size_t i = 0; i < RMT_CHANNEL_MAX; i++) {
if (!rmt_reserved_channels[i]) { if (!rmt_reserved_channels[i]) {

View File

@ -31,6 +31,7 @@
#include "driver/rmt.h" #include "driver/rmt.h"
#include <stdint.h> #include <stdint.h>
void esp32s2_peripherals_rmt_reset(void);
rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void); rmt_channel_t esp32s2_peripherals_find_and_reserve_rmt(void);
void esp32s2_peripherals_free_rmt(rmt_channel_t chan); void esp32s2_peripherals_free_rmt(rmt_channel_t chan);

View File

@ -42,6 +42,8 @@
#include "supervisor/memory.h" #include "supervisor/memory.h"
#include "supervisor/shared/tick.h" #include "supervisor/shared/tick.h"
#include "rmt.h"
STATIC esp_timer_handle_t _tick_timer; STATIC esp_timer_handle_t _tick_timer;
void tick_timer_cb(void* arg) { void tick_timer_cb(void* arg) {
@ -66,6 +68,7 @@ void reset_port(void) {
vTaskDelay(4); vTaskDelay(4);
#if CIRCUITPY_PULSEIO #if CIRCUITPY_PULSEIO
esp32s2_peripherals_rmt_reset();
pwmout_reset(); pwmout_reset();
#endif #endif
#if CIRCUITPY_BUSIO #if CIRCUITPY_BUSIO

View File

@ -64,19 +64,33 @@
//| pulse.send(pulses)""" //| pulse.send(pulses)"""
//| ... //| ...
//| //|
STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_check_num(n_args, kw_args, 1, 1, false);
mp_obj_t carrier_obj = args[0];
if (!MP_OBJ_IS_TYPE(carrier_obj, &pulseio_pwmout_type)) {
mp_raise_TypeError_varg(translate("Expected a %q"), pulseio_pwmout_type.name);
}
// create Pulse object from the given pin
pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t); pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t);
self->base.type = &pulseio_pulseout_type; self->base.type = &pulseio_pulseout_type;
#ifndef CPY_PULSEOUT_USES_DIGITALIO
// Most ports pass a PWMOut
mp_arg_check_num(n_args, kw_args, 1, 1, false);
mp_obj_t carrier_obj = args[0];
if (!MP_OBJ_IS_TYPE(carrier_obj, &pulseio_pwmout_type)) {
mp_raise_TypeError_varg(translate("Expected a %q"), pulseio_pwmout_type.name);
}
common_hal_pulseio_pulseout_construct(self, (pulseio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj)); common_hal_pulseio_pulseout_construct(self, (pulseio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj));
#else
// ESP32-S2 Special Case
enum { ARG_pin, ARG_frequency};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 38000} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mcu_pin_obj_t* pin = validate_obj_is_free_pin(args[ARG_pin].u_obj);
common_hal_pulseio_pulseout_construct(self, pin, args[ARG_frequency].u_int);
#endif
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }

View File

@ -33,8 +33,14 @@
extern const mp_obj_type_t pulseio_pulseout_type; extern const mp_obj_type_t pulseio_pulseout_type;
#ifndef CPY_PULSEOUT_USES_DIGITALIO
extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
const pulseio_pwmout_obj_t* carrier); const pulseio_pwmout_obj_t* carrier);
#else
extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
const mcu_pin_obj_t* pin, uint32_t frequency);
#endif
extern void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self); extern void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self);
extern bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self); extern bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self);
extern void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, extern void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self,