From 964cc98d144d5ff8db72e8a404534576353175c4 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 18 Jun 2018 17:52:09 +0200 Subject: [PATCH 01/18] rmt driver initial version --- cores/esp32/esp32-hal-rmt.c | 340 ++++++++++++++++++++++++++++++++++++ cores/esp32/esp32-hal-rmt.h | 63 +++++++ 2 files changed, 403 insertions(+) create mode 100644 cores/esp32/esp32-hal-rmt.c create mode 100644 cores/esp32/esp32-hal-rmt.h diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c new file mode 100644 index 00000000000..711ac2b2222 --- /dev/null +++ b/cores/esp32/esp32-hal-rmt.c @@ -0,0 +1,340 @@ +#include "esp32-hal.h" +#include "esp8266-compat.h" +#include "soc/gpio_reg.h" +#include "soc/gpio_reg.h" + +#include "esp32-hal-rmt.h" +#include "driver/periph_ctrl.h" + +#include "soc/rmt_struct.h" +#include "esp_intr_alloc.h" + + +#define MAX_CHANNELS 8 +#define ABS(a) (a>0?a:-a) + + +struct rmt_obj_s +{ + bool allocated; + intr_handle_t intr_handle; + int pin; + int channel; + bool tx_not_rx; + int buffers; +}; + +static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { + { false, NULL, 0, 0, 0, 0}, + { false, NULL, 0, 0, 0, 0}, +}; + +static intr_handle_t intr_handle; + +static bool periph_enabled = false; + +static void _initPin(int pin, int channel); + + +bool rmtDeinit(rmt_obj_t *rmt) +{ + if (!rmt) { + return false; + } + + // sanity check + if (rmt != &(g_rmt_objects[rmt->channel])) { + return false; + } + + size_t from = rmt->channel; + size_t to = rmt->buffers + rmt->channel; + size_t i; + + for (i = from; i < to; i++) { + g_rmt_objects[i].allocated = false; + } + return true; + g_rmt_objects[from].channel = 0; + g_rmt_objects[from].buffers = 0; +} + +bool rmtSend(uint32_t* data, size_t size, rmt_obj_t* rmt) +{ + if (!rmt) { + return false; + } + int channel = rmt->channel; + RMT.apb_conf.fifo_mask = 1; + size_t i; + for (i = 0; i < size; i++) { + RMTMEM.chan[channel].data32[i].val = data[i]; + } + + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + + RMT.conf_ch[channel].conf1.tx_start = 1; + + return true; +} + +rmt_obj_t* _rmtAllocate(int pin, int from, int size) +{ + size_t i; + // setup how many buffers shall we use + g_rmt_objects[from].buffers = size; + + for (i=0; ichannel; + if (ABS(apb_tick - tick) < ABS(ref_tick - tick)) { + RMT.conf_ch[channel].conf0.div_cnt = apb_div; + RMT.conf_ch[channel].conf1.ref_always_on = 1; + return apb_tick; + } else { + RMT.conf_ch[channel].conf0.div_cnt = ref_div; + RMT.conf_ch[channel].conf1.ref_always_on = 0; + return ref_tick; + } +} + +rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) +{ + int buffers = 1 + entries/64; + rmt_obj_t* rmt; + size_t i; + size_t j; + for (i=0; ipin = pin; + rmt->tx_not_rx = tx_not_rx; + rmt->buffers =buffers; + rmt->channel = channel; + _initPin(pin, channel); + + // rmt tick from 1/80M -> 12.5ns (1x) + // 3.2 us (FFx 00 is more) + // rmt tick for 1 MHz -> 1us (1x) + // 256us (00x) + + // default config (period of 1us) + RMT.conf_ch[channel].conf0.div_cnt = 1; + RMT.conf_ch[channel].conf0.mem_size = buffers; + RMT.conf_ch[channel].conf0.carrier_en = 0; + RMT.conf_ch[channel].conf0.carrier_out_lv = 0; + RMT.conf_ch[channel].conf0.mem_pd = 0; + + RMT.conf_ch[channel].conf1.rx_en = 1; + RMT.conf_ch[channel].conf1.tx_conti_mode = 0; + RMT.conf_ch[channel].conf1.ref_cnt_rst = 0; + RMT.conf_ch[channel].conf1.rx_filter_en = 0; + RMT.conf_ch[channel].conf1.rx_filter_thres = 0; + RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle + RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle + RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock + + if (tx_not_rx) { + RMT.conf_ch[channel].conf1.rx_en = 0; + RMT.conf_ch[channel].conf1.mem_owner = 0; + } else { + RMT.conf_ch[channel].conf1.rx_en = 1; + RMT.conf_ch[channel].conf1.mem_owner = 1; + } + // RMT.conf_ch[channel].conf0.val = ((uint32_t*)config)[0]; + // RMT.conf_ch[channel].conf1.val = ((uint32_t*)config)[1]; + + return rmt; +} + + + +static void _initPin(int pin, int channel) +// rmt_driver_config_t* config) +{ + if (!periph_enabled) { + periph_enabled = true; + periph_module_enable( PERIPH_RMT_MODULE ); + } + pinMode(pin, OUTPUT); + pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); + + // memcpy( (uint8_t*)&RMT.conf_ch[channel].conf0.val, (uint8_t*)config, 8); + // memcpy( (uint8_t*)&RMT.conf_ch[channel].conf1.val, ((uint8_t*)config) + 4, sizeof(uint32_t)); +} + +void initMemory(int offset, uint32_t* data, size_t size) +{ + RMT.apb_conf.fifo_mask = 1; + size_t i; + // uint16_t * ptr = (uint16_t*)&(RMTMEM.chan[offset].data16[0]); + // uint16_t * ptr = (uint16_t*)(0x3ff56800); + // // uint16_t ptr[32]; + // memset(ptr, 0, 32); + // for (i = 0; i < size; i++) { + // printf(">> %x\n", ptr[i]); + // } + + for (i = 0; i < size; i++) { + RMTMEM.chan[offset].data32[i].val = data[i]; + // printf(">> %x\n", data[i]); + // RMTMEM.chan[offset].data16[i] + // RMTMEM.chan[offset].data32[i].val = data[i]; + // printf(" %x\n", RMTMEM.chan[offset].data16[i].val); + // RMTMEM.chan[offset].data16[i] = data[i]; + // *ptr++ = i; + // ptr[i] = i; + // RMTMEM.chan[i].data1 = 0x11+ i; + // RMTMEM.chan[i].data2 = 0x22+ i; + + // printf(" %x\n", RMTMEM.chan[offset].data16[i].val); + // printf(" %x\n", RMTMEM.chan[offset].data32[i/2].val); + // printf("--------\n"); + + // printf(" %x\n", RMTMEM.chan[offset].xx.data16[i]); + // RMTMEM.chan[offset].xx.data16[i] = data[i]; + // printf(" %x\n", RMTMEM.chan[offset].xx.data16[i]); + // printf(" %x\n", RMTMEM.chan[offset].xx.data32[i/2]); + // printf("--------\n"); + + } + +} + +// 00000000 +// 00010000 + + + +void startTx(int channel) +{ + // reset rd value + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + + RMT.conf_ch[channel].conf1.tx_start = 1; +} + +// struct rmt_struct_t { +// uart_dev_t * dev; +// #if !CONFIG_DISABLE_HAL_LOCKS +// xSemaphoreHandle lock; +// #endif +// uint8_t num; +// xQueueHandle queue; +// intr_handle_t intr_handle; +// }; + +static int state = 0; + +static void IRAM_ATTR _rmt_isr(void* arg) +{ +RMT.int_clr.val = 1; +// printf("test"); +state ^= 1; +digitalWrite(4, state); +} + +int config(); + +int setpin(int pin) +{ + int channel = 0; + pinMode(pin, OUTPUT); +// *((uint32_t*)0x3FF49070) = 0x002A0000; + pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); + periph_module_enable( PERIPH_RMT_MODULE ); + +// 0x3ff49000 : 0x3FF49000 +// Address 0 - 3 4 - 7 8 - B C - F +// 3FF49000 FF030000 00080000 00080000 00080000 +// 3FF49010 00080000 00080000 00080000 00080000 +// 3FF49020 00080000 00080000 00080000 000A0000 +// 3FF49030 000A0000 800A0000 000A0000 000B0000 +// 3FF49040 800A0000 000B0000 800A0000 000A0000 +// 3FF49050 000A0000 002B0000 002B0000 002B0000 +// 3FF49060 001B0000 002B0000 002B0000 000B0000 +// 3FF49070 002A0000 000A0000 000A0000 000A0000 +// 3FF49080 000A0000 000B0000 000A0000 000A0000 +// 3FF49090 00080000 00080000 00080000 00080000 +// 3FF490A0 00080000 00080000 00080000 00080000 + +*((unsigned int*)(0x3FF560F0)) = 1; + // SET(RMT_DATA_REG, 0x8010020); + *((uint32_t*)0x3ff56800) = 0x8FFF0FFF; + *((uint32_t*)0x3ff56804) = 0x9FFF0FFF; + *((uint32_t*)0x3ff56808) = 0; + *((uint32_t*)0x3ff5680C) = 0; + *((uint32_t*)0x3ff56810) = 0; + *((uint32_t*)0x3FF560D0) = 0; + // uint32_t test = 0x8010; + // uint32_t zero = 0; + // memcpy((uint8_t*)0x3ff56800, &test, 4); + // memcpy((uint8_t*)0x3ff56804, &zero, 4); + + RMT.conf_ch[0].conf0.val = 0x01000001; + RMT.conf_ch[0].conf1.val = 0x20000; + + esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); + RMT.int_ena.val = 1; + +// RMT[0].conf0 = 0x01000001; +// // SET(RMT_CHnCONF0_REG(0), 0x31000001); +// // SET(RMT_CHnCONF1_REG(0), 0x20000); +// RMT[1].conf1 = 0x20000; + + +// 0x311000ff +//-- 0x01000ff + +// 0xa0f00 + return 1; +} + +int run() +{ +// SET(RMT_CHnCONF0_REG(0), 0x1000001); + +// *((unsigned int*)(0x3FF560F0)) = 1; +// // SET(RMT_DATA_REG, 0x8010020); +// *((uint32_t*)0x3ff56800) = 0x8010; +// *((uint32_t*)0x3ff56804) = 0; + +// SET(RMT_CHnCONF1_REG(0), 0x20009); + +return 0; + +} \ No newline at end of file diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h new file mode 100644 index 00000000000..fd022bd4ae4 --- /dev/null +++ b/cores/esp32/esp32-hal-rmt.h @@ -0,0 +1,63 @@ + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef + struct { + uint32_t div_cnt: 8; /*This register is used to configure the frequency divider's factor in channel0-7.*/ + uint32_t idle_thres: 16; /*In receive mode when no edge is detected on the input signal for longer than reg_idle_thres_ch0 then the receive process is done.*/ + uint32_t mem_size: 4; /*This register is used to configure the the amount of memory blocks allocated to channel0-7.*/ + uint32_t carrier_en: 1; /*This is the carrier modulation enable control bit for channel0-7.*/ + uint32_t carrier_out_lv: 1; /*This bit is used to configure the way carrier wave is modulated for channel0-7.1'b1:transmit on low output level 1'b0:transmit on high output level.*/ + uint32_t mem_pd: 1; /*This bit is used to reduce power consumed by memory. 1:memory is in low power state.*/ + uint32_t clk_en: 1; /*This bit is used to control clock.when software configure RMT internal registers it controls the register clock.*/ + + uint32_t tx_start: 1; /*Set this bit to start sending data for channel0-7.*/ + uint32_t rx_en: 1; /*Set this bit to enable receiving data for channel0-7.*/ + uint32_t mem_wr_rst: 1; /*Set this bit to reset write ram address for channel0-7 by receiver access.*/ + uint32_t mem_rd_rst: 1; /*Set this bit to reset read ram address for channel0-7 by transmitter access.*/ + uint32_t apb_mem_rst: 1; /*Set this bit to reset W/R ram address for channel0-7 by apb fifo access*/ + uint32_t mem_owner: 1; /*This is the mark of channel0-7's ram usage right.1'b1:receiver uses the ram 0:transmitter uses the ram*/ + uint32_t tx_conti_mode: 1; /*Set this bit to continue sending from the first data to the last data in channel0-7 again and again.*/ + uint32_t rx_filter_en: 1; /*This is the receive filter enable bit for channel0-7.*/ + uint32_t rx_filter_thres: 8; /*in receive mode channel0-7 ignore input pulse when the pulse width is smaller then this value.*/ + uint32_t ref_cnt_rst: 1; /*This bit is used to reset divider in channel0-7.*/ + uint32_t ref_always_on: 1; /*This bit is used to select base clock. 1'b1:clk_apb 1'b0:clk_ref*/ + uint32_t idle_out_lv: 1; /*This bit configures the output signal's level for channel0-7 in IDLE state.*/ + uint32_t idle_out_en: 1; /*This is the output enable control bit for channel0-7 in IDLE state.*/ + uint32_t reserved20: 12; + } rmt_driver_config_t; + + +struct rmt_obj_s; + +typedef struct rmt_obj_s rmt_obj_t; + + + +void initPin(int pin, int channel, rmt_driver_config_t* config); + +void initMemory(int offset, uint32_t* data, size_t size); + +void startTx(int channel); + + +int setpin(int pin); +int run(); + +/// + + +rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); + +float rmtSetTick(rmt_obj_t* rmt, float tick); + + +bool rmtSend(uint32_t* data, size_t size, rmt_obj_t* rmt); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file From 282deb30bb3f3f325ec8b290a9dca028a94b3cb9 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 19 Jun 2018 16:38:33 +0200 Subject: [PATCH 02/18] supporting conti mode plus interrupts --- cores/esp32/esp32-hal-rmt.c | 329 +++++++++++++++++++++++++----------- cores/esp32/esp32-hal-rmt.h | 49 ++---- 2 files changed, 243 insertions(+), 135 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 711ac2b2222..e257dda5cbc 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -11,8 +11,25 @@ #define MAX_CHANNELS 8 -#define ABS(a) (a>0?a:-a) - +#define MAX_DATA_PER_CHANNEL 64 +#define _ABS(a) (a>0?a:-a) +#define _LIMIT(a,b) (a>b?b:a) +#define __INT_TX_END (1) +#define __INT_RX_END (2) +#define __INT_ERROR (4) +#define __INT_THR_EVNT (1<<24) + +#define _INT_TX_END(channel) (__INT_TX_END<<(channel*3)) +#define _INT_RX_END(channel) (__INT_RX_END<<(channel*3)) +#define _INT_ERROR(channel) (__INT_ERROR<<(channel*3)) +#define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel)) + +typedef enum { + e_no_intr = 0, + e_tx_intr = 1, + e_txthr_intr = 2, + e_rx_intr = 4, +} intr_mode_t; struct rmt_obj_s { @@ -22,18 +39,24 @@ struct rmt_obj_s int channel; bool tx_not_rx; int buffers; + int remaining_to_send; + uint32_t* remaining_ptr; + intr_mode_t intr_mode; + }; static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { - { false, NULL, 0, 0, 0, 0}, - { false, NULL, 0, 0, 0, 0}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr}, }; static intr_handle_t intr_handle; static bool periph_enabled = false; -static void _initPin(int pin, int channel); +static void _initPin(int pin, int channel, bool tx_not_rx); + +static void IRAM_ATTR _rmt_isr(void* arg); bool rmtDeinit(rmt_obj_t *rmt) @@ -59,16 +82,101 @@ bool rmtDeinit(rmt_obj_t *rmt) g_rmt_objects[from].buffers = 0; } -bool rmtSend(uint32_t* data, size_t size, rmt_obj_t* rmt) +bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; } + int channel = rmt->channel; - RMT.apb_conf.fifo_mask = 1; + if (size > MAX_DATA_PER_CHANNEL) { + /* setup interrupts for half and full tx + */ + int half_tx_nr = MAX_DATA_PER_CHANNEL/2; + RMT.tx_lim_ch[channel].limit = half_tx_nr; + rmt->remaining_to_send = size - MAX_DATA_PER_CHANNEL; + rmt->remaining_ptr = data + MAX_DATA_PER_CHANNEL; + rmt->intr_mode = e_tx_intr | e_txthr_intr; + RMT.conf_ch[channel].conf1.tx_conti_mode = 1; + + if (!intr_handle) { + esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); + } + // clear and enable both Tx completed and half tx event + RMT.int_clr.val |= _INT_TX_END(channel); + RMT.int_clr.val |= _INT_THR_EVNT(channel); + + RMT.int_ena.val |= _INT_TX_END(channel); + RMT.int_ena.val |= _INT_THR_EVNT(channel); + return rmtSend(rmt, data, MAX_DATA_PER_CHANNEL); + + } + + + if (size < MAX_DATA_PER_CHANNEL) { + return rmtSend(rmt, data, size); + } + + return true; +} + + +bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size) +{ + if (!rmt) { + return false; + } + int channel = rmt->channel; + + if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) { + return false; + } + + // wait for the interrupt + while (!(RMT.int_raw.val&_INT_RX_END(channel))) {} + + // clear the interrupt + RMT.int_clr.val |= _INT_RX_END(channel); + size_t i; - for (i = 0; i < size; i++) { - RMTMEM.chan[channel].data32[i].val = data[i]; + volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); + for (i=0; ichannel; + + RMT.conf_ch[channel].conf0.idle_thres = idle_thres; + + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + + RMT.conf_ch[channel].conf1.rx_en = 1; + + return true; +} + + +bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) +{ + if (!rmt) { + return false; + } + int channel = rmt->channel; + RMT.apb_conf.fifo_mask = 1; + if (data && size>0) { + size_t i; + for (i = 0; i < size; i++) { + // TODO: use ptr for writing more than 1 channel mem + RMTMEM.chan[channel].data32[i].val = data[i]; + } } RMT.conf_ch[channel].conf1.mem_rd_rst = 1; @@ -97,20 +205,26 @@ float rmtSetTick(rmt_obj_t* rmt, float tick) if (!rmt) { return false; } - - int apb_div = 0xFF & (int)(tick/12.5); - int ref_div = 0xFF & (int)(tick/1000); + /* + divider field span from 1 (smallest), 2, 3, ... , 0xFF, 0x00 (highest) + * rmt tick from 1/80M -> 12.5ns (1x) div_cnt = 0x01 + 3.2 us (256x) div_cnt = 0x00 + * rmt tick for 1 MHz -> 1us (1x) div_cnt = 0x01 + 256us (256x) div_cnt = 0x00 + */ + int apb_div = _LIMIT(tick/12.5, 256); + int ref_div = _LIMIT(tick/1000, 256); float apb_tick = 12.5 * apb_div; float ref_tick = 1000.0 * ref_div; size_t channel = rmt->channel; - if (ABS(apb_tick - tick) < ABS(ref_tick - tick)) { - RMT.conf_ch[channel].conf0.div_cnt = apb_div; + if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) { + RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF; RMT.conf_ch[channel].conf1.ref_always_on = 1; return apb_tick; } else { - RMT.conf_ch[channel].conf0.div_cnt = ref_div; + RMT.conf_ch[channel].conf0.div_cnt = ref_div & 0xFF; RMT.conf_ch[channel].conf1.ref_always_on = 0; return ref_tick; } @@ -118,7 +232,7 @@ float rmtSetTick(rmt_obj_t* rmt, float tick) rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) { - int buffers = 1 + entries/64; + int buffers = 1 + entries/MAX_DATA_PER_CHANNEL; rmt_obj_t* rmt; size_t i; size_t j; @@ -135,7 +249,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) break; } } - if (i == MAX_CHANNELS) { + if (i == MAX_CHANNELS || i+j >= MAX_CHANNELS || j != buffers) { return NULL; } rmt = _rmtAllocate(pin, i, buffers); @@ -145,21 +259,20 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) rmt->tx_not_rx = tx_not_rx; rmt->buffers =buffers; rmt->channel = channel; - _initPin(pin, channel); - - // rmt tick from 1/80M -> 12.5ns (1x) - // 3.2 us (FFx 00 is more) - // rmt tick for 1 MHz -> 1us (1x) - // 256us (00x) + _initPin(pin, channel, tx_not_rx); - // default config (period of 1us) + // Initialize the registers in default mode: + // - no carrier, filter + // - timebase tick of 1us RMT.conf_ch[channel].conf0.div_cnt = 1; RMT.conf_ch[channel].conf0.mem_size = buffers; RMT.conf_ch[channel].conf0.carrier_en = 0; RMT.conf_ch[channel].conf0.carrier_out_lv = 0; RMT.conf_ch[channel].conf0.mem_pd = 0; - RMT.conf_ch[channel].conf1.rx_en = 1; + RMT.conf_ch[channel].conf1.rx_en = 0; + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; RMT.conf_ch[channel].conf1.tx_conti_mode = 0; RMT.conf_ch[channel].conf1.ref_cnt_rst = 0; RMT.conf_ch[channel].conf1.rx_filter_en = 0; @@ -169,10 +282,10 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock if (tx_not_rx) { - RMT.conf_ch[channel].conf1.rx_en = 0; + // RMT.conf_ch[channel].conf1.rx_en = 0; RMT.conf_ch[channel].conf1.mem_owner = 0; } else { - RMT.conf_ch[channel].conf1.rx_en = 1; + // RMT.conf_ch[channel].conf1.rx_en = 1; RMT.conf_ch[channel].conf1.mem_owner = 1; } // RMT.conf_ch[channel].conf0.val = ((uint32_t*)config)[0]; @@ -181,96 +294,114 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) return rmt; } - - -static void _initPin(int pin, int channel) -// rmt_driver_config_t* config) +static void _initPin(int pin, int channel, bool tx_not_rx) { if (!periph_enabled) { periph_enabled = true; periph_module_enable( PERIPH_RMT_MODULE ); } - pinMode(pin, OUTPUT); - pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); - - // memcpy( (uint8_t*)&RMT.conf_ch[channel].conf0.val, (uint8_t*)config, 8); - // memcpy( (uint8_t*)&RMT.conf_ch[channel].conf1.val, ((uint8_t*)config) + 4, sizeof(uint32_t)); -} - -void initMemory(int offset, uint32_t* data, size_t size) -{ - RMT.apb_conf.fifo_mask = 1; - size_t i; - // uint16_t * ptr = (uint16_t*)&(RMTMEM.chan[offset].data16[0]); - // uint16_t * ptr = (uint16_t*)(0x3ff56800); - // // uint16_t ptr[32]; - // memset(ptr, 0, 32); - // for (i = 0; i < size; i++) { - // printf(">> %x\n", ptr[i]); - // } - - for (i = 0; i < size; i++) { - RMTMEM.chan[offset].data32[i].val = data[i]; - // printf(">> %x\n", data[i]); - // RMTMEM.chan[offset].data16[i] - // RMTMEM.chan[offset].data32[i].val = data[i]; - // printf(" %x\n", RMTMEM.chan[offset].data16[i].val); - // RMTMEM.chan[offset].data16[i] = data[i]; - // *ptr++ = i; - // ptr[i] = i; - // RMTMEM.chan[i].data1 = 0x11+ i; - // RMTMEM.chan[i].data2 = 0x22+ i; - - // printf(" %x\n", RMTMEM.chan[offset].data16[i].val); - // printf(" %x\n", RMTMEM.chan[offset].data32[i/2].val); - // printf("--------\n"); - - // printf(" %x\n", RMTMEM.chan[offset].xx.data16[i]); - // RMTMEM.chan[offset].xx.data16[i] = data[i]; - // printf(" %x\n", RMTMEM.chan[offset].xx.data16[i]); - // printf(" %x\n", RMTMEM.chan[offset].xx.data32[i/2]); - // printf("--------\n"); + if (tx_not_rx) { + pinMode(pin, OUTPUT); + pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); + } else { + pinMode(pin, INPUT); + pinMatrixInAttach(pin, RMT_SIG_IN0_IDX + channel, 0); } - } -// 00000000 -// 00010000 - - +static int state = 0; -void startTx(int channel) +static void IRAM_ATTR _rmt_isr(void* arg) { - // reset rd value - RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + digitalWrite(4, 1); - RMT.conf_ch[channel].conf1.tx_start = 1; -} + int intr_val = RMT.int_st.val; + size_t ch; + for (ch=0; ch half_tx_nr) { + g_rmt_objects[ch].remaining_to_send -= half_tx_nr; + g_rmt_objects[ch].remaining_ptr += half_tx_nr; + } else { + // mark transaction completed + g_rmt_objects[ch].intr_mode = e_no_intr; + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + + // TODO ... a callback or event? + } + } else { + // REPORT error + } + } + if (intr_val&_INT_THR_EVNT(ch)) { + + RMT.int_clr.val |= _INT_THR_EVNT(ch); + + if ((g_rmt_objects[ch].intr_mode)&e_txthr_intr) { + // have to copy the remaining bytes + size_t i; + int half_tx_nr = MAX_DATA_PER_CHANNEL/2; + uint32_t* data = g_rmt_objects[ch].remaining_ptr; + + // prepare the data to send + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = data[i]; + } + + // check for the transaction end + if (g_rmt_objects[ch].remaining_to_send > half_tx_nr) { + g_rmt_objects[ch].remaining_to_send -= half_tx_nr; + g_rmt_objects[ch].remaining_ptr += half_tx_nr; + } else { + // mark transaction completed + g_rmt_objects[ch].intr_mode = e_no_intr; + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + + // TODO ... a callback or event? + } + } else { + // REPORT error + } + } -static void IRAM_ATTR _rmt_isr(void* arg) -{ -RMT.int_clr.val = 1; -// printf("test"); -state ^= 1; -digitalWrite(4, state); + } + // switch (RMT.int_st.val) + // RMT.int_clr.val = 1; + // state ^= 1; + digitalWrite(4, 0); } int config(); -int setpin(int pin) +int setxpin(int pin) { int channel = 0; pinMode(pin, OUTPUT); diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index fd022bd4ae4..5592b5fe666 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -3,49 +3,19 @@ extern "C" { #endif - -typedef - struct { - uint32_t div_cnt: 8; /*This register is used to configure the frequency divider's factor in channel0-7.*/ - uint32_t idle_thres: 16; /*In receive mode when no edge is detected on the input signal for longer than reg_idle_thres_ch0 then the receive process is done.*/ - uint32_t mem_size: 4; /*This register is used to configure the the amount of memory blocks allocated to channel0-7.*/ - uint32_t carrier_en: 1; /*This is the carrier modulation enable control bit for channel0-7.*/ - uint32_t carrier_out_lv: 1; /*This bit is used to configure the way carrier wave is modulated for channel0-7.1'b1:transmit on low output level 1'b0:transmit on high output level.*/ - uint32_t mem_pd: 1; /*This bit is used to reduce power consumed by memory. 1:memory is in low power state.*/ - uint32_t clk_en: 1; /*This bit is used to control clock.when software configure RMT internal registers it controls the register clock.*/ - - uint32_t tx_start: 1; /*Set this bit to start sending data for channel0-7.*/ - uint32_t rx_en: 1; /*Set this bit to enable receiving data for channel0-7.*/ - uint32_t mem_wr_rst: 1; /*Set this bit to reset write ram address for channel0-7 by receiver access.*/ - uint32_t mem_rd_rst: 1; /*Set this bit to reset read ram address for channel0-7 by transmitter access.*/ - uint32_t apb_mem_rst: 1; /*Set this bit to reset W/R ram address for channel0-7 by apb fifo access*/ - uint32_t mem_owner: 1; /*This is the mark of channel0-7's ram usage right.1'b1:receiver uses the ram 0:transmitter uses the ram*/ - uint32_t tx_conti_mode: 1; /*Set this bit to continue sending from the first data to the last data in channel0-7 again and again.*/ - uint32_t rx_filter_en: 1; /*This is the receive filter enable bit for channel0-7.*/ - uint32_t rx_filter_thres: 8; /*in receive mode channel0-7 ignore input pulse when the pulse width is smaller then this value.*/ - uint32_t ref_cnt_rst: 1; /*This bit is used to reset divider in channel0-7.*/ - uint32_t ref_always_on: 1; /*This bit is used to select base clock. 1'b1:clk_apb 1'b0:clk_ref*/ - uint32_t idle_out_lv: 1; /*This bit configures the output signal's level for channel0-7 in IDLE state.*/ - uint32_t idle_out_en: 1; /*This is the output enable control bit for channel0-7 in IDLE state.*/ - uint32_t reserved20: 12; - } rmt_driver_config_t; - - struct rmt_obj_s; typedef struct rmt_obj_s rmt_obj_t; +// void initPin(int pin, int channel, rmt_driver_config_t* config); -void initPin(int pin, int channel, rmt_driver_config_t* config); - -void initMemory(int offset, uint32_t* data, size_t size); - -void startTx(int channel); +// void initMemory(int offset, uint32_t* data, size_t size); +// void startTx(int channel); -int setpin(int pin); -int run(); +// int setpin(int pin); +// int run(); /// @@ -54,8 +24,15 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); float rmtSetTick(rmt_obj_t* rmt, float tick); +bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size); + +bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size); + + +bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres); + +bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); -bool rmtSend(uint32_t* data, size_t size, rmt_obj_t* rmt); #ifdef __cplusplus From 16f4d12c975bd6f8ebc1b1c79b0cd583f8543b26 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 21 Jun 2018 17:06:36 +0200 Subject: [PATCH 03/18] using conitnous mode for sending more data --- cores/esp32/esp32-hal-rmt.c | 305 +++++++++++++++++++++++++++++++----- 1 file changed, 266 insertions(+), 39 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index e257dda5cbc..c4dc2b8c712 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -12,6 +12,7 @@ #define MAX_CHANNELS 8 #define MAX_DATA_PER_CHANNEL 64 +#define MAX_DATA_PER_ITTERATION 20 #define _ABS(a) (a>0?a:-a) #define _LIMIT(a,b) (a>b?b:a) #define __INT_TX_END (1) @@ -29,6 +30,8 @@ typedef enum { e_tx_intr = 1, e_txthr_intr = 2, e_rx_intr = 4, + e_end_trans = 8, + } intr_mode_t; struct rmt_obj_s @@ -82,6 +85,8 @@ bool rmtDeinit(rmt_obj_t *rmt) g_rmt_objects[from].buffers = 0; } +volatile int fake_transaction = 0; + bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { @@ -89,26 +94,77 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) } int channel = rmt->channel; - if (size > MAX_DATA_PER_CHANNEL) { + // if (size > MAX_DATA_PER_CHANNEL) { + if (size > MAX_DATA_PER_ITTERATION) { /* setup interrupts for half and full tx */ - int half_tx_nr = MAX_DATA_PER_CHANNEL/2; - RMT.tx_lim_ch[channel].limit = half_tx_nr; - rmt->remaining_to_send = size - MAX_DATA_PER_CHANNEL; - rmt->remaining_ptr = data + MAX_DATA_PER_CHANNEL; - rmt->intr_mode = e_tx_intr | e_txthr_intr; - RMT.conf_ch[channel].conf1.tx_conti_mode = 1; - if (!intr_handle) { esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); } +#if 0 + digitalWrite(2, 1); + RMT.apb_conf.fifo_mask = 1; + int i; + for (i = 0; i< 5; i++) { + RMTMEM.chan[channel].data32[i].val = 0x00010001; + } + // RMT.conf_ch[channel].conf1.tx_conti_mode = 1; + // RMT.int_clr.val |= _INT_TX_END(channel); + // RMT.int_ena.val |= _INT_TX_END(channel); + // fake_transaction = 1; + // while (fake_transaction != 3 ) { } + + + RMTMEM.chan[channel].data32[i].val = 0; + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + RMT.conf_ch[channel].conf1.mem_rd_rst = 0; + fake_transaction = 1; + RMT.conf_ch[channel].conf1.tx_conti_mode = 1; + RMT.int_clr.val |= _INT_TX_END(channel); + RMT.int_ena.val |= _INT_TX_END(channel); + + RMT.conf_ch[channel].conf1.tx_start = 1; + while (fake_transaction != 3 ) { } + // RMT.conf_ch[channel].conf1.tx_conti_mode = 0; + // fake_transaction = 1; + // while (!(RMT.int_raw.val&_INT_TX_END(channel))) { } + digitalWrite(2, 1); + RMT.int_clr.val |= _INT_TX_END(channel); + + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + RMT.conf_ch[channel].conf1.mem_rd_rst = 0; + // fake_transaction = 1; + // while (fake_transaction != 2) { } + RMT.int_clr.val |= _INT_TX_END(channel); + digitalWrite(2, 0); +#endif + + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + RMT.tx_lim_ch[channel].limit = half_tx_nr; + rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; + rmt->remaining_ptr = data + MAX_DATA_PER_ITTERATION; + rmt->intr_mode = e_tx_intr | e_txthr_intr; + // RMT.conf_ch[channel].conf1.apb_mem_rst = 1; + // RMT.conf_ch[channel].conf1.apb_mem_rst = 0; + // RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + // RMT.conf_ch[channel].conf1.mem_rd_rst = 0; + // RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + // RMT.conf_ch[channel].conf1.mem_wr_rst = 0; + RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0; + fake_transaction = 1; + // RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + + // clear and enable both Tx completed and half tx event RMT.int_clr.val |= _INT_TX_END(channel); RMT.int_clr.val |= _INT_THR_EVNT(channel); + RMT.int_clr.val |= _INT_ERROR(channel); + RMT.int_ena.val |= _INT_TX_END(channel); RMT.int_ena.val |= _INT_THR_EVNT(channel); - return rmtSend(rmt, data, MAX_DATA_PER_CHANNEL); + RMT.int_ena.val |= _INT_ERROR(channel); + return rmtSend(rmt, data, MAX_DATA_PER_ITTERATION); } @@ -177,6 +233,7 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) // TODO: use ptr for writing more than 1 channel mem RMTMEM.chan[channel].data32[i].val = data[i]; } + RMTMEM.chan[channel].data32[size].val = 0; } RMT.conf_ch[channel].conf1.mem_rd_rst = 1; @@ -271,8 +328,6 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) RMT.conf_ch[channel].conf0.mem_pd = 0; RMT.conf_ch[channel].conf1.rx_en = 0; - RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - RMT.conf_ch[channel].conf1.mem_wr_rst = 1; RMT.conf_ch[channel].conf1.tx_conti_mode = 0; RMT.conf_ch[channel].conf1.ref_cnt_rst = 0; RMT.conf_ch[channel].conf1.rx_filter_en = 0; @@ -284,9 +339,11 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) if (tx_not_rx) { // RMT.conf_ch[channel].conf1.rx_en = 0; RMT.conf_ch[channel].conf1.mem_owner = 0; + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; } else { // RMT.conf_ch[channel].conf1.rx_en = 1; RMT.conf_ch[channel].conf1.mem_owner = 1; + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; } // RMT.conf_ch[channel].conf0.val = ((uint32_t*)config)[0]; // RMT.conf_ch[channel].conf1.val = ((uint32_t*)config)[1]; @@ -314,7 +371,7 @@ static int state = 0; static void IRAM_ATTR _rmt_isr(void* arg) { - digitalWrite(4, 1); + // digitalWrite(4, 1); int intr_val = RMT.int_st.val; size_t ch; @@ -327,69 +384,237 @@ static void IRAM_ATTR _rmt_isr(void* arg) // REPORT error } } + if (intr_val&_INT_ERROR(ch)) { + + // digitalWrite(4, 1); + ets_printf("Error!\n"); + + + RMT.int_clr.val |= _INT_ERROR(ch); + RMT.conf_ch[ch].conf1.mem_rd_rst = 1; + RMT.conf_ch[ch].conf1.mem_rd_rst = 0; + } if (intr_val&_INT_TX_END(ch)) { RMT.int_clr.val |= _INT_TX_END(ch); - +#if 0 + if (fake_transaction == 1) { + digitalWrite(4, 1); + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + fake_transaction++; + // RMT.int_ena.val &= ~_INT_TX_END(ch); + } else if (fake_transaction == 2) { + digitalWrite(4, 1); + fake_transaction++; + RMT.int_ena.val &= ~_INT_TX_END(ch); + } else +#endif + { + digitalWrite(2, 1); + ets_printf("Tx_End!\n"); + if (RMT.conf_ch[ch].conf1.tx_conti_mode) { + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } else { + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + } + + } + + // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + // RMTMEM.chan[ch].data32[15].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + + + RMT.int_clr.val |= _INT_TX_END(ch); + #if 0 + // RMT.conf_ch[ch].conf1.mem_rd_rst = 1; + // // RMT.conf_ch[ch].conf1.mem_rd_rst = 0; + // RMTMEM.chan[ch].data32[20].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + + // RMT.int_ena.val &= ~_INT_TX_END(ch); + + if ((g_rmt_objects[ch].intr_mode)&e_end_trans) { + g_rmt_objects[ch].intr_mode = e_no_intr; + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMTMEM.chan[ch].data32[0].val = 0; + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } + if ((g_rmt_objects[ch].intr_mode)&e_tx_intr) { // have to copy the remaining bytes size_t i; - int half_tx_nr = MAX_DATA_PER_CHANNEL/2; + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; uint32_t* data = g_rmt_objects[ch].remaining_ptr; - - // prepare the data to send - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i+half_tx_nr].val = data[i]; - } + int remaining_size = g_rmt_objects[ch].remaining_to_send; // check for the transaction end - if (g_rmt_objects[ch].remaining_to_send > half_tx_nr) { + if (remaining_size > half_tx_nr) { g_rmt_objects[ch].remaining_to_send -= half_tx_nr; g_rmt_objects[ch].remaining_ptr += half_tx_nr; + // prepare the data to send + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i+half_tx_nr].val = data[i]; + } } else { // mark transaction completed - g_rmt_objects[ch].intr_mode = e_no_intr; - RMT.int_ena.val &= ~_INT_TX_END(ch); - RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - + g_rmt_objects[ch].intr_mode |= e_end_trans; + + // g_rmt_objects[ch].intr_mode = e_no_intr; + // RMT.int_ena.val &= ~_INT_TX_END(ch); + // RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; + // prepare the data to send + for (i = 0; i < remaining_size; i++) { + RMTMEM.chan[ch].data32[i+half_tx_nr].val = data[i]; + } + // mark end transaction + size_t transaction_end_mark = (i+half_tx_nr>=MAX_DATA_PER_ITTERATION)?0:i+half_tx_nr; + RMTMEM.chan[ch].data32[transaction_end_mark].val = 0; // TODO ... a callback or event? } } else { // REPORT error } + #endif } if (intr_val&_INT_THR_EVNT(ch)) { + digitalWrite(4, 1); + + // RMT.conf_ch[ch].conf1.mem_rd_rst = 1; + // RMT.conf_ch[ch].conf1.mem_rd_rst = 0; + // RMTMEM.chan[ch].data32[25].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + if (fake_transaction == 1) { + + RMT.conf_ch[ch].conf1.tx_conti_mode = 1; + fake_transaction = 2; + } + RMT.int_clr.val |= _INT_THR_EVNT(ch); + uint32_t* data = g_rmt_objects[ch].remaining_ptr; + if (data) + { + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0x000F000F; + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+1].val = 0x000F000F; + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+2].val = 0x000F000F; + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+3].val = 0x000F000F; + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+4].val = 0x000F000F; + // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+5].val = 0x0; + int remaining_size = g_rmt_objects[ch].remaining_to_send; + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + if (remaining_size > half_tx_nr) { + if (!state) { + RMTMEM.chan[ch].data32[0].val = data[0] - 1; + for (i = 1; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = data[i]; + } + } else { + for (i = 0; i < MAX_DATA_PER_ITTERATION; i++) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; + } + } + g_rmt_objects[ch].remaining_to_send -= half_tx_nr; + state ^= 1; + } else { + RMTMEM.chan[ch].data32[0].val = data[0] - 1; + for (i = 1; i < MAX_DATA_PER_ITTERATION; i++) { + if (i < half_tx_nr) { + if (i < remaining_size) { + RMTMEM.chan[ch].data32[i].val = data[i]; + } else { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + } else { + // RMTMEM.chan[ch].data32[i].val = data[i%4]; + } + } + // RMTMEM.chan[ch].data32[half_tx_nr].val = 0x000F000F; + RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; + g_rmt_objects[ch].remaining_ptr = NULL; + } + + // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } else { + // ets_printf("Finish\n"); + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + for (i = half_tx_nr; i < MAX_DATA_PER_ITTERATION; i++) { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + #if 0 + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + for (i = 0; i < MAX_DATA_PER_ITTERATION; i++) { + if (i < half_tx_nr) { + // RMTMEM.chan[ch].data32[i].val = 0x80050005; + } else { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + } + RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; + #endif + + // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } + + #if 0 + + if ((g_rmt_objects[ch].intr_mode)&e_end_trans) { + g_rmt_objects[ch].intr_mode = e_no_intr; + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMTMEM.chan[ch].data32[0].val = 0; + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } + if ((g_rmt_objects[ch].intr_mode)&e_txthr_intr) { // have to copy the remaining bytes size_t i; - int half_tx_nr = MAX_DATA_PER_CHANNEL/2; + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; uint32_t* data = g_rmt_objects[ch].remaining_ptr; - - // prepare the data to send - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i].val = data[i]; - } - + int remaining_size = g_rmt_objects[ch].remaining_to_send; // check for the transaction end - if (g_rmt_objects[ch].remaining_to_send > half_tx_nr) { + if (remaining_size > half_tx_nr) { g_rmt_objects[ch].remaining_to_send -= half_tx_nr; g_rmt_objects[ch].remaining_ptr += half_tx_nr; - } else { - // mark transaction completed - g_rmt_objects[ch].intr_mode = e_no_intr; - RMT.int_ena.val &= ~_INT_TX_END(ch); - RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + // prepare the data to send + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = data[i]; + } + } else + { + // mark transaction completed + g_rmt_objects[ch].intr_mode |= e_end_trans; + + // g_rmt_objects[ch].intr_mode = e_no_intr; + // // RMT.int_ena.val &= ~_INT_TX_END(ch); + // RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + // // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; + // prepare the data to send + // for (i = 0; i < remaining_size; i++) { + // RMTMEM.chan[ch].data32[i].val = data[i]; + // } + // mark end transaction + RMTMEM.chan[ch].data32[remaining_size].val = 0; + // RMTMEM.chan[ch].data32[remaining_size+1].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + // RMTMEM.chan[ch].data32[0].val = 0; + // RMTMEM.chan[ch].data32[0+1].val = 0; // TODO ... a callback or event? } } else { // REPORT error } + #endif } } @@ -397,6 +622,8 @@ static void IRAM_ATTR _rmt_isr(void* arg) // RMT.int_clr.val = 1; // state ^= 1; digitalWrite(4, 0); + digitalWrite(2, 0); + } int config(); From 488ca06455a17919a60472f081a925cdcba26e5e Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 22 Jun 2018 10:19:09 +0200 Subject: [PATCH 04/18] working continous mode --- cores/esp32/esp32-hal-rmt.c | 146 +++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 36 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index c4dc2b8c712..79ba1377e3f 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -12,7 +12,7 @@ #define MAX_CHANNELS 8 #define MAX_DATA_PER_CHANNEL 64 -#define MAX_DATA_PER_ITTERATION 20 +#define MAX_DATA_PER_ITTERATION 40 #define _ABS(a) (a>0?a:-a) #define _LIMIT(a,b) (a>b?b:a) #define __INT_TX_END (1) @@ -31,6 +31,7 @@ typedef enum { e_txthr_intr = 2, e_rx_intr = 4, e_end_trans = 8, + e_set_conti = 0x10, } intr_mode_t; @@ -54,6 +55,8 @@ static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { }; static intr_handle_t intr_handle; +static int state = 0; + static bool periph_enabled = false; @@ -138,18 +141,18 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) RMT.int_clr.val |= _INT_TX_END(channel); digitalWrite(2, 0); #endif - + state = 0; int half_tx_nr = MAX_DATA_PER_ITTERATION/2; RMT.tx_lim_ch[channel].limit = half_tx_nr; rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; rmt->remaining_ptr = data + MAX_DATA_PER_ITTERATION; - rmt->intr_mode = e_tx_intr | e_txthr_intr; - // RMT.conf_ch[channel].conf1.apb_mem_rst = 1; - // RMT.conf_ch[channel].conf1.apb_mem_rst = 0; - // RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - // RMT.conf_ch[channel].conf1.mem_rd_rst = 0; - // RMT.conf_ch[channel].conf1.mem_wr_rst = 1; - // RMT.conf_ch[channel].conf1.mem_wr_rst = 0; + rmt->intr_mode = e_tx_intr | e_txthr_intr | e_set_conti; + RMT.conf_ch[channel].conf1.apb_mem_rst = 1; + RMT.conf_ch[channel].conf1.apb_mem_rst = 0; + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + RMT.conf_ch[channel].conf1.mem_rd_rst = 0; + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + RMT.conf_ch[channel].conf1.mem_wr_rst = 0; RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0; fake_transaction = 1; // RMT.conf_ch[channel].conf1.mem_wr_rst = 1; @@ -310,6 +313,9 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) return NULL; } rmt = _rmtAllocate(pin, i, buffers); + if (!intr_handle) { + esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); + } size_t channel = i; rmt->pin = pin; @@ -367,7 +373,6 @@ static void _initPin(int pin, int channel, bool tx_not_rx) } } -static int state = 0; static void IRAM_ATTR _rmt_isr(void* arg) { @@ -387,6 +392,8 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val&_INT_ERROR(ch)) { // digitalWrite(4, 1); + digitalWrite(2, 1); + ets_printf("Error!\n"); @@ -410,14 +417,26 @@ static void IRAM_ATTR _rmt_isr(void* arg) } else #endif { - digitalWrite(2, 1); - ets_printf("Tx_End!\n"); - if (RMT.conf_ch[ch].conf1.tx_conti_mode) { + // digitalWrite(2, 1); + // ets_printf("Tx_End!\n"); + if (g_rmt_objects[ch].intr_mode&e_end_trans) { + ets_printf("Tx_End marked !\n"); RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - } else { - RMT.int_ena.val &= ~_INT_TX_END(ch); - RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + g_rmt_objects[ch].intr_mode = e_no_intr; + + } else if (g_rmt_objects[ch].intr_mode == e_no_intr) { + ets_printf("Tx completed !\n"); + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); } + // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + + // if (RMT.conf_ch[ch].conf1.tx_conti_mode) { + // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + // } else { + // RMT.int_ena.val &= ~_INT_TX_END(ch); + // RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + // } } @@ -487,13 +506,23 @@ static void IRAM_ATTR _rmt_isr(void* arg) // RMT.conf_ch[ch].conf1.mem_rd_rst = 0; // RMTMEM.chan[ch].data32[25].val = 0; // RMTMEM.chan[ch].data32[0].val = 0; - if (fake_transaction == 1) { + // if (fake_transaction == 1) { + + // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; + // fake_transaction = 2; + // } + if (g_rmt_objects[ch].intr_mode&e_set_conti) { RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - fake_transaction = 2; + g_rmt_objects[ch].intr_mode &= ~e_set_conti; } + // if (!RMT.conf_ch[ch].conf1.tx_conti_mode) { + // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; + // } + + RMT.int_clr.val |= _INT_THR_EVNT(ch); uint32_t* data = g_rmt_objects[ch].remaining_ptr; @@ -510,42 +539,87 @@ static void IRAM_ATTR _rmt_isr(void* arg) int i; if (remaining_size > half_tx_nr) { if (!state) { + // ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[i].val = data[i]; } } else { - for (i = 0; i < MAX_DATA_PER_ITTERATION; i++) { + // ets_printf("second\n"); + for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; } } g_rmt_objects[ch].remaining_to_send -= half_tx_nr; + g_rmt_objects[ch].remaining_ptr += half_tx_nr; state ^= 1; } else { - RMTMEM.chan[ch].data32[0].val = data[0] - 1; - for (i = 1; i < MAX_DATA_PER_ITTERATION; i++) { - if (i < half_tx_nr) { + // ets_printf("last chunk..."); + if (!state) { + // ets_printf("first\n"); + RMTMEM.chan[ch].data32[0].val = data[0] - 1; + for (i = 1; i < half_tx_nr; i++) { if (i < remaining_size) { RMTMEM.chan[ch].data32[i].val = data[i]; } else { RMTMEM.chan[ch].data32[i].val = 0x000F000F; } - } else { - // RMTMEM.chan[ch].data32[i].val = data[i%4]; } - } - // RMTMEM.chan[ch].data32[half_tx_nr].val = 0x000F000F; - RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; - g_rmt_objects[ch].remaining_ptr = NULL; - } + // RMTMEM.chan[ch].data32[i].val = 0; + } else { + // ets_printf("second\n"); + for (i = 0; i < half_tx_nr; i++) { + if (i < remaining_size) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; + } else { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; + } + } + // RMTMEM.chan[ch].data32[i].val = 0; + } + state ^= 1; + RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; + g_rmt_objects[ch].remaining_ptr = NULL; + + // for (i = 1; i < MAX_DATA_PER_ITTERATION; i++) { + // if (i < half_tx_nr) { + // if (i < remaining_size) { + // RMTMEM.chan[ch].data32[i].val = data[i]; + // } else { + // RMTMEM.chan[ch].data32[i].val = 0x000F000F; + // } + // } else { + // // RMTMEM.chan[ch].data32[i].val = data[i%4]; + // } + } + // RMTMEM.chan[ch].data32[half_tx_nr].val = 0x000F000F; + } else { + if ((!(g_rmt_objects[ch].intr_mode&e_end_trans)) && (g_rmt_objects[ch].intr_mode != e_no_intr)) { + // ets_printf("tail (empty)"); + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + if (!state) { + // ets_printf("...first\n"); + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[i].val = 0; - // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - } else { - // ets_printf("Finish\n"); - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - int i; - for (i = half_tx_nr; i < MAX_DATA_PER_ITTERATION; i++) { - RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } else { + // ets_printf("...second\n"); + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[i].val = 0; + } + // int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + // int i; + // for (i = half_tx_nr; i < MAX_DATA_PER_ITTERATION; i++) { + // RMTMEM.chan[ch].data32[i].val = 0x000F000F; + // } + g_rmt_objects[ch].intr_mode |= e_end_trans; + } else { + // ets_printf("do_nothing\n"); } #if 0 int half_tx_nr = MAX_DATA_PER_ITTERATION/2; From c2a669fc21b5bb3a100e617a7d2332e94ea7a788 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 22 Jun 2018 11:12:22 +0200 Subject: [PATCH 05/18] rmt driver cleanup after conti mode --- cores/esp32/esp32-hal-rmt.c | 458 +++++++----------------------------- cores/esp32/esp32-hal-rmt.h | 20 +- 2 files changed, 94 insertions(+), 384 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 79ba1377e3f..3c0625e3650 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -30,11 +30,17 @@ typedef enum { e_tx_intr = 1, e_txthr_intr = 2, e_rx_intr = 4, - e_end_trans = 8, - e_set_conti = 0x10, - } intr_mode_t; +typedef enum { + e_inactive = 0, + e_first_half = 1, + e_last_data = 2, + e_end_trans = 4, + e_set_conti = 8, +} transaction_state_t; + + struct rmt_obj_s { bool allocated; @@ -46,12 +52,12 @@ struct rmt_obj_s int remaining_to_send; uint32_t* remaining_ptr; intr_mode_t intr_mode; - + transaction_state_t tx_state; }; static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, }; static intr_handle_t intr_handle; @@ -83,12 +89,11 @@ bool rmtDeinit(rmt_obj_t *rmt) for (i = from; i < to; i++) { g_rmt_objects[i].allocated = false; } - return true; g_rmt_objects[from].channel = 0; g_rmt_objects[from].buffers = 0; -} -volatile int fake_transaction = 0; + return true; +} bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) { @@ -97,86 +102,49 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) } int channel = rmt->channel; - // if (size > MAX_DATA_PER_CHANNEL) { + if (size > MAX_DATA_PER_ITTERATION) { - /* setup interrupts for half and full tx - */ + // if (size > MAX_DATA_PER_CHANNEL) { + + // setup interrupt handler if not yet installed for half and full tx if (!intr_handle) { esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); } -#if 0 - digitalWrite(2, 1); - RMT.apb_conf.fifo_mask = 1; - int i; - for (i = 0; i< 5; i++) { - RMTMEM.chan[channel].data32[i].val = 0x00010001; - } - // RMT.conf_ch[channel].conf1.tx_conti_mode = 1; - // RMT.int_clr.val |= _INT_TX_END(channel); - // RMT.int_ena.val |= _INT_TX_END(channel); - // fake_transaction = 1; - // while (fake_transaction != 3 ) { } - - - RMTMEM.chan[channel].data32[i].val = 0; - RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - RMT.conf_ch[channel].conf1.mem_rd_rst = 0; - fake_transaction = 1; - RMT.conf_ch[channel].conf1.tx_conti_mode = 1; - RMT.int_clr.val |= _INT_TX_END(channel); - RMT.int_ena.val |= _INT_TX_END(channel); - - RMT.conf_ch[channel].conf1.tx_start = 1; - while (fake_transaction != 3 ) { } - // RMT.conf_ch[channel].conf1.tx_conti_mode = 0; - // fake_transaction = 1; - // while (!(RMT.int_raw.val&_INT_TX_END(channel))) { } - digitalWrite(2, 1); - RMT.int_clr.val |= _INT_TX_END(channel); - RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - RMT.conf_ch[channel].conf1.mem_rd_rst = 0; - // fake_transaction = 1; - // while (fake_transaction != 2) { } - RMT.int_clr.val |= _INT_TX_END(channel); - digitalWrite(2, 0); -#endif - state = 0; int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - RMT.tx_lim_ch[channel].limit = half_tx_nr; rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; rmt->remaining_ptr = data + MAX_DATA_PER_ITTERATION; - rmt->intr_mode = e_tx_intr | e_txthr_intr | e_set_conti; + rmt->intr_mode = e_tx_intr | e_txthr_intr; + rmt->tx_state = e_set_conti | e_first_half; + + // init the tx limit for interruption + RMT.tx_lim_ch[channel].limit = half_tx_nr; + // reset memory pointer RMT.conf_ch[channel].conf1.apb_mem_rst = 1; RMT.conf_ch[channel].conf1.apb_mem_rst = 0; RMT.conf_ch[channel].conf1.mem_rd_rst = 1; RMT.conf_ch[channel].conf1.mem_rd_rst = 0; RMT.conf_ch[channel].conf1.mem_wr_rst = 1; RMT.conf_ch[channel].conf1.mem_wr_rst = 0; + + // set the tx end mark RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0; - fake_transaction = 1; - // RMT.conf_ch[channel].conf1.mem_wr_rst = 1; - - + // clear and enable both Tx completed and half tx event RMT.int_clr.val |= _INT_TX_END(channel); RMT.int_clr.val |= _INT_THR_EVNT(channel); RMT.int_clr.val |= _INT_ERROR(channel); - RMT.int_ena.val |= _INT_TX_END(channel); RMT.int_ena.val |= _INT_THR_EVNT(channel); RMT.int_ena.val |= _INT_ERROR(channel); - return rmtSend(rmt, data, MAX_DATA_PER_ITTERATION); - } - - - if (size < MAX_DATA_PER_CHANNEL) { + // start the transation + return rmtSend(rmt, data, MAX_DATA_PER_ITTERATION); + } else { + // use one-go mode if data fits one buffer return rmtSend(rmt, data, size); } - - return true; } @@ -232,10 +200,11 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) RMT.apb_conf.fifo_mask = 1; if (data && size>0) { size_t i; + volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); for (i = 0; i < size; i++) { - // TODO: use ptr for writing more than 1 channel mem - RMTMEM.chan[channel].data32[i].val = data[i]; + *rmt_mem_ptr++ = data[i]; } + // tx end mark RMTMEM.chan[channel].data32[size].val = 0; } @@ -246,7 +215,7 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) return true; } -rmt_obj_t* _rmtAllocate(int pin, int from, int size) +static rmt_obj_t* _rmtAllocate(int pin, int from, int size) { size_t i; // setup how many buffers shall we use @@ -313,9 +282,6 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) return NULL; } rmt = _rmtAllocate(pin, i, buffers); - if (!intr_handle) { - esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); - } size_t channel = i; rmt->pin = pin; @@ -351,8 +317,11 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) RMT.conf_ch[channel].conf1.mem_owner = 1; RMT.conf_ch[channel].conf1.mem_wr_rst = 1; } - // RMT.conf_ch[channel].conf0.val = ((uint32_t*)config)[0]; - // RMT.conf_ch[channel].conf1.val = ((uint32_t*)config)[1]; + + // install interrupt if at least one channel is active + if (!intr_handle) { + esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); + } return rmt; } @@ -376,186 +345,96 @@ static void _initPin(int pin, int channel, bool tx_not_rx) static void IRAM_ATTR _rmt_isr(void* arg) { - // digitalWrite(4, 1); + digitalWrite(4, 1); int intr_val = RMT.int_st.val; size_t ch; for (ch=0; ch half_tx_nr) { - g_rmt_objects[ch].remaining_to_send -= half_tx_nr; - g_rmt_objects[ch].remaining_ptr += half_tx_nr; - // prepare the data to send - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i+half_tx_nr].val = data[i]; - } - } else { - // mark transaction completed - g_rmt_objects[ch].intr_mode |= e_end_trans; - - // g_rmt_objects[ch].intr_mode = e_no_intr; - // RMT.int_ena.val &= ~_INT_TX_END(ch); - // RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - // prepare the data to send - for (i = 0; i < remaining_size; i++) { - RMTMEM.chan[ch].data32[i+half_tx_nr].val = data[i]; - } - // mark end transaction - size_t transaction_end_mark = (i+half_tx_nr>=MAX_DATA_PER_ITTERATION)?0:i+half_tx_nr; - RMTMEM.chan[ch].data32[transaction_end_mark].val = 0; - // TODO ... a callback or event? - } - } else { - // REPORT error + g_rmt_objects[ch].intr_mode = e_no_intr; + g_rmt_objects[ch].tx_state = e_inactive; } - #endif } - if (intr_val&_INT_THR_EVNT(ch)) { - digitalWrite(4, 1); - // RMT.conf_ch[ch].conf1.mem_rd_rst = 1; - // RMT.conf_ch[ch].conf1.mem_rd_rst = 0; - // RMTMEM.chan[ch].data32[25].val = 0; - // RMTMEM.chan[ch].data32[0].val = 0; - - // if (fake_transaction == 1) { + if (intr_val&_INT_THR_EVNT(ch)) { + // clear the flag + RMT.int_clr.val |= _INT_THR_EVNT(ch); - // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - // fake_transaction = 2; - // } - if (g_rmt_objects[ch].intr_mode&e_set_conti) { + // initial setup of continuous mode + if (g_rmt_objects[ch].tx_state&e_set_conti) { RMT.conf_ch[ch].conf1.tx_conti_mode = 1; g_rmt_objects[ch].intr_mode &= ~e_set_conti; } - - // if (!RMT.conf_ch[ch].conf1.tx_conti_mode) { - // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - // } - - - RMT.int_clr.val |= _INT_THR_EVNT(ch); - + // check if still any data to be sent uint32_t* data = g_rmt_objects[ch].remaining_ptr; if (data) { - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0x000F000F; - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+1].val = 0x000F000F; - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+2].val = 0x000F000F; - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+3].val = 0x000F000F; - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+4].val = 0x000F000F; - // RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION+5].val = 0x0; int remaining_size = g_rmt_objects[ch].remaining_to_send; int half_tx_nr = MAX_DATA_PER_ITTERATION/2; int i; + + // will the remaining data occupy the entire halfbuffer if (remaining_size > half_tx_nr) { - if (!state) { + if (g_rmt_objects[ch].tx_state&e_first_half) { // ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[i].val = data[i]; } + g_rmt_objects[ch].tx_state &= ~e_first_half; } else { // ets_printf("second\n"); for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; } + g_rmt_objects[ch].tx_state |= e_first_half; } g_rmt_objects[ch].remaining_to_send -= half_tx_nr; g_rmt_objects[ch].remaining_ptr += half_tx_nr; - state ^= 1; } else { + // less remaining data than buffer size -> fill in with fake (inactive) pulses // ets_printf("last chunk..."); - if (!state) { + if (g_rmt_objects[ch].tx_state&e_first_half) { // ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { @@ -565,7 +444,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMTMEM.chan[ch].data32[i].val = 0x000F000F; } } - // RMTMEM.chan[ch].data32[i].val = 0; + g_rmt_objects[ch].tx_state &= ~e_first_half; } else { // ets_printf("second\n"); for (i = 0; i < half_tx_nr; i++) { @@ -575,198 +454,41 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; } } - // RMTMEM.chan[ch].data32[i].val = 0; + g_rmt_objects[ch].tx_state |= e_first_half; } - state ^= 1; RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; + // mark g_rmt_objects[ch].remaining_ptr = NULL; - - // for (i = 1; i < MAX_DATA_PER_ITTERATION; i++) { - // if (i < half_tx_nr) { - // if (i < remaining_size) { - // RMTMEM.chan[ch].data32[i].val = data[i]; - // } else { - // RMTMEM.chan[ch].data32[i].val = 0x000F000F; - // } - // } else { - // // RMTMEM.chan[ch].data32[i].val = data[i%4]; - // } - } - // RMTMEM.chan[ch].data32[half_tx_nr].val = 0x000F000F; - } else { - if ((!(g_rmt_objects[ch].intr_mode&e_end_trans)) && (g_rmt_objects[ch].intr_mode != e_no_intr)) { + } + } else { + // no data left, just copy the fake (inactive) pulses + if ( (!(g_rmt_objects[ch].tx_state&e_last_data)) && + (!(g_rmt_objects[ch].tx_state&e_end_trans)) ) { // ets_printf("tail (empty)"); int half_tx_nr = MAX_DATA_PER_ITTERATION/2; int i; - if (!state) { + if (g_rmt_objects[ch].tx_state&e_first_half) { // ets_printf("...first\n"); for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[i].val = 0x000F000F; } RMTMEM.chan[ch].data32[i].val = 0; - + g_rmt_objects[ch].tx_state &= ~e_first_half; } else { // ets_printf("...second\n"); for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; } RMTMEM.chan[ch].data32[i].val = 0; + g_rmt_objects[ch].tx_state |= e_first_half; } - // int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - // int i; - // for (i = half_tx_nr; i < MAX_DATA_PER_ITTERATION; i++) { - // RMTMEM.chan[ch].data32[i].val = 0x000F000F; - // } - g_rmt_objects[ch].intr_mode |= e_end_trans; + g_rmt_objects[ch].tx_state |= e_last_data; } else { // ets_printf("do_nothing\n"); } - #if 0 - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - int i; - for (i = 0; i < MAX_DATA_PER_ITTERATION; i++) { - if (i < half_tx_nr) { - // RMTMEM.chan[ch].data32[i].val = 0x80050005; - } else { - RMTMEM.chan[ch].data32[i].val = 0x000F000F; - } - } - RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; - #endif - - // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; } - - #if 0 - - if ((g_rmt_objects[ch].intr_mode)&e_end_trans) { - g_rmt_objects[ch].intr_mode = e_no_intr; - RMT.int_ena.val &= ~_INT_TX_END(ch); - RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - RMTMEM.chan[ch].data32[0].val = 0; - RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - } - - if ((g_rmt_objects[ch].intr_mode)&e_txthr_intr) { - // have to copy the remaining bytes - size_t i; - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - uint32_t* data = g_rmt_objects[ch].remaining_ptr; - int remaining_size = g_rmt_objects[ch].remaining_to_send; - // check for the transaction end - if (remaining_size > half_tx_nr) { - g_rmt_objects[ch].remaining_to_send -= half_tx_nr; - g_rmt_objects[ch].remaining_ptr += half_tx_nr; - // prepare the data to send - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i].val = data[i]; - } - - } else - { - // mark transaction completed - g_rmt_objects[ch].intr_mode |= e_end_trans; - - // g_rmt_objects[ch].intr_mode = e_no_intr; - // // RMT.int_ena.val &= ~_INT_TX_END(ch); - // RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - // // RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - // RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - // prepare the data to send - // for (i = 0; i < remaining_size; i++) { - // RMTMEM.chan[ch].data32[i].val = data[i]; - // } - // mark end transaction - RMTMEM.chan[ch].data32[remaining_size].val = 0; - // RMTMEM.chan[ch].data32[remaining_size+1].val = 0; - // RMTMEM.chan[ch].data32[0].val = 0; - // RMTMEM.chan[ch].data32[0].val = 0; - // RMTMEM.chan[ch].data32[0].val = 0; - // RMTMEM.chan[ch].data32[0+1].val = 0; - // TODO ... a callback or event? - } - } else { - // REPORT error - } - #endif } - } - // switch (RMT.int_st.val) - // RMT.int_clr.val = 1; - // state ^= 1; digitalWrite(4, 0); digitalWrite(2, 0); - -} - -int config(); - -int setxpin(int pin) -{ - int channel = 0; - pinMode(pin, OUTPUT); -// *((uint32_t*)0x3FF49070) = 0x002A0000; - pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0); - periph_module_enable( PERIPH_RMT_MODULE ); - -// 0x3ff49000 : 0x3FF49000 -// Address 0 - 3 4 - 7 8 - B C - F -// 3FF49000 FF030000 00080000 00080000 00080000 -// 3FF49010 00080000 00080000 00080000 00080000 -// 3FF49020 00080000 00080000 00080000 000A0000 -// 3FF49030 000A0000 800A0000 000A0000 000B0000 -// 3FF49040 800A0000 000B0000 800A0000 000A0000 -// 3FF49050 000A0000 002B0000 002B0000 002B0000 -// 3FF49060 001B0000 002B0000 002B0000 000B0000 -// 3FF49070 002A0000 000A0000 000A0000 000A0000 -// 3FF49080 000A0000 000B0000 000A0000 000A0000 -// 3FF49090 00080000 00080000 00080000 00080000 -// 3FF490A0 00080000 00080000 00080000 00080000 - -*((unsigned int*)(0x3FF560F0)) = 1; - // SET(RMT_DATA_REG, 0x8010020); - *((uint32_t*)0x3ff56800) = 0x8FFF0FFF; - *((uint32_t*)0x3ff56804) = 0x9FFF0FFF; - *((uint32_t*)0x3ff56808) = 0; - *((uint32_t*)0x3ff5680C) = 0; - *((uint32_t*)0x3ff56810) = 0; - *((uint32_t*)0x3FF560D0) = 0; - // uint32_t test = 0x8010; - // uint32_t zero = 0; - // memcpy((uint8_t*)0x3ff56800, &test, 4); - // memcpy((uint8_t*)0x3ff56804, &zero, 4); - - RMT.conf_ch[0].conf0.val = 0x01000001; - RMT.conf_ch[0].conf1.val = 0x20000; - - esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); - RMT.int_ena.val = 1; - -// RMT[0].conf0 = 0x01000001; -// // SET(RMT_CHnCONF0_REG(0), 0x31000001); -// // SET(RMT_CHnCONF1_REG(0), 0x20000); -// RMT[1].conf1 = 0x20000; - - -// 0x311000ff -//-- 0x01000ff - -// 0xa0f00 - return 1; } - -int run() -{ -// SET(RMT_CHnCONF0_REG(0), 0x1000001); - -// *((unsigned int*)(0x3FF560F0)) = 1; -// // SET(RMT_DATA_REG, 0x8010020); -// *((uint32_t*)0x3ff56800) = 0x8010; -// *((uint32_t*)0x3ff56804) = 0; - -// SET(RMT_CHnCONF1_REG(0), 0x20009); - -return 0; - -} \ No newline at end of file diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 5592b5fe666..6ac281b65b7 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -7,19 +7,10 @@ struct rmt_obj_s; typedef struct rmt_obj_s rmt_obj_t; - -// void initPin(int pin, int channel, rmt_driver_config_t* config); - -// void initMemory(int offset, uint32_t* data, size_t size); - -// void startTx(int channel); - -// int setpin(int pin); -// int run(); - -/// - - +/** +* Initialize the object +* +*/ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); float rmtSetTick(rmt_obj_t* rmt, float tick); @@ -28,13 +19,10 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size); bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size); - bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres); bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); - - #ifdef __cplusplus } #endif \ No newline at end of file From 23e45a4ffb46979c44e5042fd2a0f0649dcba5cb Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 22 Jun 2018 15:35:04 +0200 Subject: [PATCH 06/18] initial version of rmt driver --- cores/esp32/esp32-hal-rmt.c | 74 ++++++++++++++++++++++++++++++++++--- cores/esp32/esp32-hal-rmt.h | 17 +++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 3c0625e3650..ef27def9614 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -1,3 +1,6 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" + #include "esp32-hal.h" #include "esp8266-compat.h" #include "soc/gpio_reg.h" @@ -44,7 +47,7 @@ typedef enum { struct rmt_obj_s { bool allocated; - intr_handle_t intr_handle; + EventGroupHandle_t events; int pin; int channel; bool tx_not_rx; @@ -61,8 +64,6 @@ static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { }; static intr_handle_t intr_handle; -static int state = 0; - static bool periph_enabled = false; @@ -181,6 +182,11 @@ bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres) } int channel = rmt->channel; + RMT.int_clr.val |= _INT_ERROR(channel); + + RMT.int_ena.val |= _INT_ERROR(channel); + + RMT.conf_ch[channel].conf1.mem_owner = 1; RMT.conf_ch[channel].conf0.idle_thres = idle_thres; RMT.conf_ch[channel].conf1.mem_wr_rst = 1; @@ -190,6 +196,45 @@ bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres) return true; } +bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t size, void* eventFlag) +{ + if (!rmt) { + return false; + } + int channel = rmt->channel; + + if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) { + return false; + } + + if (eventFlag) { + xEventGroupClearBits(eventFlag, RMT_FLAGS_ALL); + rmt->events = eventFlag; + } + + if (data && size>0) { + rmt->remaining_ptr = data; + rmt->remaining_to_send = size; + } + + rmt->intr_mode = e_rx_intr; + + RMT.conf_ch[channel].conf1.mem_owner = 1; + RMT.conf_ch[channel].conf0.idle_thres = idle_thres; + + RMT.int_clr.val |= _INT_RX_END(channel); + RMT.int_clr.val |= _INT_ERROR(channel); + + RMT.int_ena.val |= _INT_RX_END(channel); + RMT.int_ena.val |= _INT_ERROR(channel); + + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + + RMT.conf_ch[channel].conf1.rx_en = 1; + + return true; +} + bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) { @@ -354,10 +399,20 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val&_INT_RX_END(ch)) { // clear the flag RMT.int_clr.val |= _INT_RX_END(ch); - // if ((g_rmt_objects[ch].intr_mode)&e_rx_intr) { - // Not yet implemented + + if (g_rmt_objects[ch].events) { + xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_RX_DONE); + } + if (g_rmt_objects[ch].remaining_ptr && g_rmt_objects[ch].remaining_to_send > 0) { + size_t i; + for (i = 0; i < g_rmt_objects[ch].remaining_to_send; i++ ) { + *(g_rmt_objects[ch].remaining_ptr)++ = RMTMEM.chan[ch].data32[i].val; + } + } + g_rmt_objects[ch].intr_mode &= ~e_rx_intr; + } else { // Report error and disable Rx interrupt ets_printf("Unexpected Rx interrupt!\n"); @@ -368,11 +423,18 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val&_INT_ERROR(ch)) { // clear the flag RMT.int_clr.val |= _INT_ERROR(ch); + RMT.int_ena.val &= ~_INT_ERROR(ch); // report error - ets_printf("RMT Error!\n"); + ets_printf("RMT Error %d!\n", ch); + if (g_rmt_objects[ch].events) { + xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR); + } + // reset memory RMT.conf_ch[ch].conf1.mem_rd_rst = 1; RMT.conf_ch[ch].conf1.mem_rd_rst = 0; + RMT.conf_ch[ch].conf1.mem_wr_rst = 1; + RMT.conf_ch[ch].conf1.mem_wr_rst = 0; } if (intr_val&_INT_TX_END(ch)) { diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 6ac281b65b7..4362fd77294 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -3,6 +3,12 @@ extern "C" { #endif +// notification flags +#define RMT_FLAG_TX_DONE (1) +#define RMT_FLAG_RX_DONE (2) +#define RMT_FLAG_ERROR (4) +#define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR) + struct rmt_obj_s; typedef struct rmt_obj_s rmt_obj_t; @@ -21,8 +27,19 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size); bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres); +bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t size, void* event_flags); + bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); + +// TODO: +// * carrier interface +// * mutexes +// * uninstall interrupt when all channels are deinit +// * send only-conti mode with circular-buffer +// * put sanity checks to some macro or inlines +// * doxy comments + #ifdef __cplusplus } #endif \ No newline at end of file From 2e76fc0348e7b088f0e286ade4fa642ae20a58d6 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Fri, 22 Jun 2018 16:18:15 +0200 Subject: [PATCH 07/18] adding a simple example --- cores/esp32/esp32-hal-rmt.h | 28 ++++++++- .../examples/RMTLoopback/RMTLoopbakc.ino | 63 +++++++++++++++++++ 2 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 4362fd77294..9a834504fa0 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -1,4 +1,3 @@ - #ifdef __cplusplus extern "C" { #endif @@ -19,17 +18,42 @@ typedef struct rmt_obj_s rmt_obj_t; */ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); +/** +* Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds +* return the real actual tick value in ns +*/ float rmtSetTick(rmt_obj_t* rmt, float tick); +/** +* Sending data in one-go mode (more data must span over multiple channels) +* +*/ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size); +/** +* Sending data in one-go mode (more data being send while updating buffers in interrupts) +* +*/ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size); +/** +* Initiates simple data receive without interrupts +* +*/ bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres); +/** +* Wait method for synchronous receive +* +*/ +bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); + +/** +* Initiates async receive, event flag indicates data received +* +*/ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t size, void* event_flags); -bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); // TODO: diff --git a/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino b/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino new file mode 100644 index 00000000000..1092287d674 --- /dev/null +++ b/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino @@ -0,0 +1,63 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "Arduino.h" + +#include "esp32-hal-rmt.h" + +uint32_t my_data[256]; + +uint32_t data[256]; + +rmt_obj_t* rmt_send = NULL; +rmt_obj_t* rmt_recv = NULL; + + +void setup() +{ + if ((rmt_send = rmtInit(18, true, 2, 1000)) == NULL) + { + printf("init sender failed\n"); + } + if ((rmt_recv = rmtInit(21, false, 2, 1000)) == NULL) + { + printf("init receiver failed\n"); + } + + + float realTick = rmtSetTick(rmt_send, 400); + printf("real tick set to: %f\n", realTick); + realTick = rmtSetTick(rmt_recv, 400); + printf("real tick set to: %f\n", realTick); + + events = xEventGroupCreate(); +} + +void loop() +{ + // Init data + int i; + for (i=0; i<255; i++) { + data[i] = 0x80010001 + ((i%13)<<16) + 13-(i%13); + } + data[255] = 0; + + // Start receiving + rmtReceiveAsync(rmt_recv, 0x4F, my_data, 60, events); + + // Send in continous mode + rmtSendQueued(rmt_send, data, 56); + + // Wait for data + xEventGroupWaitBits(events, RMT_FLAG_RX_DONE, 1, 1, portMAX_DELAY); + + // Printout the received data plus the original values + for (i=0; i<60; i++) + { + printf("%08x=%08x ", my_data[i], data[i] ); + if (!((i+1)%4)) printf("\n"); + } + printf("\n"); + + delay(2000); +} From d2f3e69b126af4016a45239236756cae689be6cd Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 25 Jun 2018 07:56:33 +0200 Subject: [PATCH 08/18] adding channel and block locks --- cores/esp32/esp32-hal-rmt.c | 67 ++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index ef27def9614..0d98f279a1c 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -1,5 +1,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" +#include "freertos/semphr.h" #include "esp32-hal.h" #include "esp8266-compat.h" @@ -28,6 +29,14 @@ #define _INT_ERROR(channel) (__INT_ERROR<<(channel*3)) #define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel)) +#if CONFIG_DISABLE_HAL_LOCKS +# define UART_MUTEX_LOCK(channel) +# define UART_MUTEX_UNLOCK(channel) +#else +# define RMT_MUTEX_LOCK(channel) do {} while (xSemaphoreTake(g_rmt_objlocks[channel], portMAX_DELAY) != pdPASS) +# define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel]) +#endif /* CONFIG_DISABLE_HAL_LOCKS */ + typedef enum { e_no_intr = 0, e_tx_intr = 1, @@ -58,15 +67,28 @@ struct rmt_obj_s transaction_state_t tx_state; }; +static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, }; static intr_handle_t intr_handle; static bool periph_enabled = false; +static xSemaphoreHandle g_rmt_block_lock = NULL; + + static void _initPin(int pin, int channel, bool tx_not_rx); static void IRAM_ATTR _rmt_isr(void* arg); @@ -84,6 +106,13 @@ bool rmtDeinit(rmt_obj_t *rmt) } size_t from = rmt->channel; + +#if !CONFIG_DISABLE_HAL_LOCKS + if(g_rmt_objlocks[from] != NULL) { + vSemaphoreDelete(g_rmt_objlocks[from]); + } +#endif + size_t to = rmt->buffers + rmt->channel; size_t i; @@ -106,13 +135,13 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) if (size > MAX_DATA_PER_ITTERATION) { // if (size > MAX_DATA_PER_CHANNEL) { - + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + RMT_MUTEX_LOCK(channel); // setup interrupt handler if not yet installed for half and full tx if (!intr_handle) { esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); } - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; rmt->remaining_ptr = data + MAX_DATA_PER_ITTERATION; rmt->intr_mode = e_tx_intr | e_txthr_intr; @@ -140,6 +169,8 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) RMT.int_ena.val |= _INT_THR_EVNT(channel); RMT.int_ena.val |= _INT_ERROR(channel); + RMT_MUTEX_UNLOCK(channel); + // start the transation return rmtSend(rmt, data, MAX_DATA_PER_ITTERATION); } else { @@ -217,6 +248,7 @@ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t s rmt->remaining_to_send = size; } + RMT_MUTEX_LOCK(channel); rmt->intr_mode = e_rx_intr; RMT.conf_ch[channel].conf1.mem_owner = 1; @@ -231,6 +263,7 @@ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t s RMT.conf_ch[channel].conf1.mem_wr_rst = 1; RMT.conf_ch[channel].conf1.rx_en = 1; + RMT_MUTEX_UNLOCK(channel); return true; } @@ -253,9 +286,10 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) RMTMEM.chan[channel].data32[size].val = 0; } + RMT_MUTEX_LOCK(channel); RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - RMT.conf_ch[channel].conf1.tx_start = 1; + RMT_MUTEX_UNLOCK(channel); return true; } @@ -292,7 +326,8 @@ float rmtSetTick(rmt_obj_t* rmt, float tick) float apb_tick = 12.5 * apb_div; float ref_tick = 1000.0 * ref_div; - size_t channel = rmt->channel; + size_t channel = rmt->channel; + if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) { RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF; RMT.conf_ch[channel].conf1.ref_always_on = 1; @@ -310,6 +345,14 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) rmt_obj_t* rmt; size_t i; size_t j; + + // create common block mutex for protecting allocs from multiple threads + if (!g_rmt_block_lock) { + g_rmt_block_lock = xSemaphoreCreateMutex(); + } + // lock + while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {} + for (i=0; i= MAX_CHANNELS || j != buffers) { + xSemaphoreGive(g_rmt_block_lock); return NULL; } rmt = _rmtAllocate(pin, i, buffers); + xSemaphoreGive(g_rmt_block_lock); + size_t channel = i; + +#if !CONFIG_DISABLE_HAL_LOCKS + if(g_rmt_objlocks[channel] == NULL) { + g_rmt_objlocks[channel] = xSemaphoreCreateMutex(); + if(g_rmt_objlocks[channel] == NULL) { + return NULL; + } + } +#endif + + RMT_MUTEX_LOCK(channel); + rmt->pin = pin; rmt->tx_not_rx = tx_not_rx; rmt->buffers =buffers; @@ -367,6 +425,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) if (!intr_handle) { esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); } + RMT_MUTEX_UNLOCK(channel); return rmt; } From f1c1dd67dd2979280468895bf72e1632f7cc67d1 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 25 Jun 2018 18:05:30 +0200 Subject: [PATCH 09/18] modified of rmt interface for simpler/easier usage --- cores/esp32/esp32-hal-rmt.c | 20 ++++++++++++-------- cores/esp32/esp32-hal-rmt.h | 29 +++++++++++++++++------------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 0d98f279a1c..7a209e53d31 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -91,6 +91,9 @@ static xSemaphoreHandle g_rmt_block_lock = NULL; static void _initPin(int pin, int channel, bool tx_not_rx); +static bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size); + + static void IRAM_ATTR _rmt_isr(void* arg); @@ -125,16 +128,17 @@ bool rmtDeinit(rmt_obj_t *rmt) return true; } -bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool rmtSent(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; } int channel = rmt->channel; + int allocated_size = 64 * rmt->buffers; + + if (size > allocated_size) { - if (size > MAX_DATA_PER_ITTERATION) { - // if (size > MAX_DATA_PER_CHANNEL) { int half_tx_nr = MAX_DATA_PER_ITTERATION/2; RMT_MUTEX_LOCK(channel); // setup interrupt handler if not yet installed for half and full tx @@ -172,10 +176,10 @@ bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size) RMT_MUTEX_UNLOCK(channel); // start the transation - return rmtSend(rmt, data, MAX_DATA_PER_ITTERATION); + return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION); } else { // use one-go mode if data fits one buffer - return rmtSend(rmt, data, size); + return _rmtSendOnce(rmt, data, size); } } @@ -269,7 +273,7 @@ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t s } -bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; @@ -339,9 +343,9 @@ float rmtSetTick(rmt_obj_t* rmt, float tick) } } -rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period) +rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) { - int buffers = 1 + entries/MAX_DATA_PER_CHANNEL; + int buffers = memsize; rmt_obj_t* rmt; size_t i; size_t j; diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index 9a834504fa0..acab80eed5a 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -10,13 +10,24 @@ extern "C" { struct rmt_obj_s; +typedef enum { + e_reserve_64_items = 1, + e_reserve_128_items = 2, + e_reserve_192_items = 3, + e_reserve_256_items = 4, + e_reserve_320_items = 5, + e_reserve_384_items = 6, + e_reserve_448_items = 7, + e_reserve_512_items = 8, +} rmt_reserve_memsize_t; + typedef struct rmt_obj_s rmt_obj_t; /** * Initialize the object * */ -rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); +rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize); /** * Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds @@ -25,22 +36,17 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, int entries, int period); float rmtSetTick(rmt_obj_t* rmt, float tick); /** -* Sending data in one-go mode (more data must span over multiple channels) +* Sending data in one-go mode or continual mode +* (more data being send while updating buffers in interrupts) * */ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size); -/** -* Sending data in one-go mode (more data being send while updating buffers in interrupts) -* -*/ -bool rmtSendQueued(rmt_obj_t* rmt, uint32_t* data, size_t size); - /** * Initiates simple data receive without interrupts * */ -bool rmtReceive(rmt_obj_t* rmt, size_t idle_thres); +bool rmtBeginReceive(rmt_obj_t* rmt, size_t idle_thres); /** * Wait method for synchronous receive @@ -54,11 +60,10 @@ bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size); */ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t size, void* event_flags); - - // TODO: +// * add timeout to waiForData +// * try to eliminate idle_thres from the receiving functions // * carrier interface -// * mutexes // * uninstall interrupt when all channels are deinit // * send only-conti mode with circular-buffer // * put sanity checks to some macro or inlines From 826ef0ef3a341dd75aff12b01c0f8d626dec1ce1 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 26 Jun 2018 09:11:06 +0200 Subject: [PATCH 10/18] adding header sentinels, split interface to common and additional settings --- cores/esp32/esp32-hal-rmt.c | 191 +++++++++++++++++++++++++----------- cores/esp32/esp32-hal-rmt.h | 32 ++++-- 2 files changed, 158 insertions(+), 65 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 7a209e53d31..4749df0f76a 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -1,3 +1,6 @@ +#ifndef MAIN_ESP32_HAL_RMT_H_ +#define MAIN_ESP32_HAL_RMT_H_ + #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" #include "freertos/semphr.h" @@ -13,7 +16,9 @@ #include "soc/rmt_struct.h" #include "esp_intr_alloc.h" - +/** + * Internal macros + */ #define MAX_CHANNELS 8 #define MAX_DATA_PER_CHANNEL 64 #define MAX_DATA_PER_ITTERATION 40 @@ -37,6 +42,9 @@ # define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel]) #endif /* CONFIG_DISABLE_HAL_LOCKS */ +/** + * Typedefs for internal stuctures, enums + */ typedef enum { e_no_intr = 0, e_tx_intr = 1, @@ -52,7 +60,6 @@ typedef enum { e_set_conti = 8, } transaction_state_t; - struct rmt_obj_s { bool allocated; @@ -67,6 +74,9 @@ struct rmt_obj_s transaction_state_t tx_state; }; +/** + * Internal variables for channel descriptors + */ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -82,20 +92,68 @@ static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, }; +/** + * Internal variables for driver data + */ static intr_handle_t intr_handle; static bool periph_enabled = false; static xSemaphoreHandle g_rmt_block_lock = NULL; - +/** + * Internal method (private) declarations + */ static void _initPin(int pin, int channel, bool tx_not_rx); static bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size); - static void IRAM_ATTR _rmt_isr(void* arg); +bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size); + +static rmt_obj_t* _rmtAllocate(int pin, int from, int size); + +static void _initPin(int pin, int channel, bool tx_not_rx); + + +/** + * Public method definitions + */ +bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high) +{ + if (!rmt || low > 0xFFFF || high > 0xFFFF) { + return false; + } + size_t channel = rmt->channel; + + RMT_MUTEX_LOCK(channel); + + RMT.carrier_duty_ch[channel].low = low; + RMT.carrier_duty_ch[channel].low = high; + RMT.conf_ch[channel].conf0.carrier_en = carrier_en; + RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level; + + RMT_MUTEX_UNLOCK(channel); + + return true; + +} + +bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value) +{ + if (!rmt || value > 0xFFFF) { + return false; + } + size_t channel = rmt->channel; + + RMT_MUTEX_LOCK(channel); + RMT.conf_ch[channel].conf0.idle_thres = value; + RMT_MUTEX_UNLOCK(channel); + + return true; +} + bool rmtDeinit(rmt_obj_t *rmt) { @@ -128,7 +186,7 @@ bool rmtDeinit(rmt_obj_t *rmt) return true; } -bool rmtSent(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; @@ -184,7 +242,7 @@ bool rmtSent(rmt_obj_t* rmt, uint32_t* data, size_t size) } -bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool rmtGetData(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; @@ -195,12 +253,6 @@ bool rmtWaitForData(rmt_obj_t* rmt, uint32_t* data, size_t size) return false; } - // wait for the interrupt - while (!(RMT.int_raw.val&_INT_RX_END(channel))) {} - - // clear the interrupt - RMT.int_clr.val |= _INT_RX_END(channel); - size_t i; volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); for (i=0; ichannel; RMT.int_clr.val |= _INT_ERROR(channel); - RMT.int_ena.val |= _INT_ERROR(channel); RMT.conf_ch[channel].conf1.mem_owner = 1; - RMT.conf_ch[channel].conf0.idle_thres = idle_thres; - RMT.conf_ch[channel].conf1.mem_wr_rst = 1; - RMT.conf_ch[channel].conf1.rx_en = 1; return true; } -bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t size, void* eventFlag) +bool rmtReceiveCompleted(rmt_obj_t* rmt) +{ + if (!rmt) { + return false; + } + int channel = rmt->channel; + + if (RMT.int_raw.val&_INT_RX_END(channel)) { + // RX end flag + RMT.int_clr.val |= _INT_RX_END(channel); + return true; + } else { + return false; + } +} + +bool rmtReceive(rmt_obj_t* rmt, uint32_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) { if (!rmt) { return false; @@ -256,7 +320,6 @@ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t s rmt->intr_mode = e_rx_intr; RMT.conf_ch[channel].conf1.mem_owner = 1; - RMT.conf_ch[channel].conf0.idle_thres = idle_thres; RMT.int_clr.val |= _INT_RX_END(channel); RMT.int_clr.val |= _INT_ERROR(channel); @@ -269,49 +332,18 @@ bool rmtReceiveAsync(rmt_obj_t* rmt, size_t idle_thres, uint32_t* data, size_t s RMT.conf_ch[channel].conf1.rx_en = 1; RMT_MUTEX_UNLOCK(channel); - return true; -} - - -bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size) -{ - if (!rmt) { - return false; - } - int channel = rmt->channel; - RMT.apb_conf.fifo_mask = 1; - if (data && size>0) { - size_t i; - volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); - for (i = 0; i < size; i++) { - *rmt_mem_ptr++ = data[i]; + // wait for data if requested so + if (waitForData && eventFlag) { + uint32_t flags = xEventGroupWaitBits(eventFlag, RMT_FLAGS_ALL, + pdTRUE /* clear on exit */, pdFALSE /* wait for all bits */, timeout); + if (flags & RMT_FLAG_ERROR) { + return false; } - // tx end mark - RMTMEM.chan[channel].data32[size].val = 0; } - RMT_MUTEX_LOCK(channel); - RMT.conf_ch[channel].conf1.mem_rd_rst = 1; - RMT.conf_ch[channel].conf1.tx_start = 1; - RMT_MUTEX_UNLOCK(channel); - return true; } -static rmt_obj_t* _rmtAllocate(int pin, int from, int size) -{ - size_t i; - // setup how many buffers shall we use - g_rmt_objects[from].buffers = size; - - for (i=0; ichannel; + RMT.apb_conf.fifo_mask = 1; + if (data && size>0) { + size_t i; + volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); + for (i = 0; i < size; i++) { + *rmt_mem_ptr++ = data[i]; + } + // tx end mark + RMTMEM.chan[channel].data32[size].val = 0; + } + + RMT_MUTEX_LOCK(channel); + RMT.conf_ch[channel].conf1.mem_rd_rst = 1; + RMT.conf_ch[channel].conf1.tx_start = 1; + RMT_MUTEX_UNLOCK(channel); + + return true; +} + + +static rmt_obj_t* _rmtAllocate(int pin, int from, int size) +{ + size_t i; + // setup how many buffers shall we use + g_rmt_objects[from].buffers = size; + + for (i=0; i Date: Fri, 29 Jun 2018 15:05:35 +0200 Subject: [PATCH 11/18] Fixes per code review + support for rx callback mode --- cores/esp32/esp32-hal-rmt.c | 211 +++++++++++++----- cores/esp32/esp32-hal-rmt.h | 52 ++++- .../examples/RMTLoopback/RMTLoopbakc.ino | 34 +-- 3 files changed, 209 insertions(+), 88 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 4749df0f76a..48d8b58b810 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -72,6 +72,8 @@ struct rmt_obj_s uint32_t* remaining_ptr; intr_mode_t intr_mode; transaction_state_t tx_state; + rmt_rx_data_cb_t cb; + bool data_alloc; }; /** @@ -82,14 +84,14 @@ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { }; static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, }; /** @@ -106,16 +108,16 @@ static xSemaphoreHandle g_rmt_block_lock = NULL; */ static void _initPin(int pin, int channel, bool tx_not_rx); -static bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size); +static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size); static void IRAM_ATTR _rmt_isr(void* arg); -bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size); - static rmt_obj_t* _rmtAllocate(int pin, int from, int size); static void _initPin(int pin, int channel, bool tx_not_rx); +static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel); + /** * Public method definitions @@ -140,6 +142,24 @@ bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t } +bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) +{ + if (!rmt || filter_level > 0xFF) { + return false; + } + size_t channel = rmt->channel; + + RMT_MUTEX_LOCK(channel); + + RMT.conf_ch[channel].conf1.rx_filter_thres = filter_level; + RMT.conf_ch[channel].conf1.rx_filter_en = filter_en; + + RMT_MUTEX_UNLOCK(channel); + + return true; + +} + bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value) { if (!rmt || value > 0xFFFF) { @@ -186,7 +206,7 @@ bool rmtDeinit(rmt_obj_t *rmt) return true; } -bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) { if (!rmt) { return false; @@ -205,7 +225,7 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) } rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; - rmt->remaining_ptr = data + MAX_DATA_PER_ITTERATION; + rmt->remaining_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION; rmt->intr_mode = e_tx_intr | e_txthr_intr; rmt->tx_state = e_set_conti | e_first_half; @@ -242,7 +262,7 @@ bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size) } -bool rmtGetData(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { return false; @@ -295,7 +315,41 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt) } } -bool rmtReceive(rmt_obj_t* rmt, uint32_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) +bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) +{ + if (!rmt && !cb) { + return false; + } + int channel = rmt->channel; + + RMT_MUTEX_LOCK(channel); + rmt->intr_mode = e_rx_intr; + rmt->tx_state = e_first_half; + rmt->cb = cb; + // allocate internally two buffers which would alternate + if (!rmt->data_alloc) { + rmt->remaining_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t)); + rmt->remaining_to_send = MAX_DATA_PER_CHANNEL*rmt->buffers; + rmt->data_alloc = true; + } + + RMT.conf_ch[channel].conf1.mem_owner = 1; + + RMT.int_clr.val = _INT_RX_END(channel); + RMT.int_clr.val = _INT_ERROR(channel); + + RMT.int_ena.val |= _INT_RX_END(channel); + RMT.int_ena.val |= _INT_ERROR(channel); + + RMT.conf_ch[channel].conf1.mem_wr_rst = 1; + + RMT.conf_ch[channel].conf1.rx_en = 1; + RMT_MUTEX_UNLOCK(channel); + + return true; +} + +bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout) { if (!rmt) { return false; @@ -312,7 +366,7 @@ bool rmtReceive(rmt_obj_t* rmt, uint32_t* data, size_t size, void* eventFlag, bo } if (data && size>0) { - rmt->remaining_ptr = data; + rmt->remaining_ptr = (uint32_t*)data; rmt->remaining_to_send = size; } @@ -321,8 +375,8 @@ bool rmtReceive(rmt_obj_t* rmt, uint32_t* data, size_t size, void* eventFlag, bo RMT.conf_ch[channel].conf1.mem_owner = 1; - RMT.int_clr.val |= _INT_RX_END(channel); - RMT.int_clr.val |= _INT_ERROR(channel); + RMT.int_clr.val = _INT_RX_END(channel); + RMT.int_clr.val = _INT_ERROR(channel); RMT.int_ena.val |= _INT_RX_END(channel); RMT.int_ena.val |= _INT_ERROR(channel); @@ -439,7 +493,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) RMT.conf_ch[channel].conf0.carrier_out_lv = 0; RMT.conf_ch[channel].conf0.mem_pd = 0; - RMT.conf_ch[channel].conf0.idle_thres = 0x8000; + RMT.conf_ch[channel].conf0.idle_thres = 0x80; RMT.conf_ch[channel].conf1.rx_en = 0; RMT.conf_ch[channel].conf1.tx_conti_mode = 0; RMT.conf_ch[channel].conf1.ref_cnt_rst = 0; @@ -448,6 +502,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock + RMT.apb_conf.fifo_mask = 1; if (tx_not_rx) { // RMT.conf_ch[channel].conf1.rx_en = 0; @@ -471,7 +526,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize) /** * Private methods definitions */ -bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size) +bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size) { if (!rmt) { return false; @@ -482,7 +537,7 @@ bool _rmtSendOnce(rmt_obj_t* rmt, uint32_t* data, size_t size) size_t i; volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val); for (i = 0; i < size; i++) { - *rmt_mem_ptr++ = data[i]; + *rmt_mem_ptr++ = data[i].val; } // tx end mark RMTMEM.chan[channel].data32[size].val = 0; @@ -534,42 +589,66 @@ static void IRAM_ATTR _rmt_isr(void* arg) int intr_val = RMT.int_st.val; size_t ch; - for (ch=0; ch 0) { size_t i; + uint32_t * data = g_rmt_objects[ch].remaining_ptr; + if (g_rmt_objects[ch].cb) { + if (g_rmt_objects[ch].tx_state&e_first_half) { + g_rmt_objects[ch].tx_state &= ~e_first_half; + } else { + g_rmt_objects[ch].tx_state |= e_first_half; + data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers); + } + } for (i = 0; i < g_rmt_objects[ch].remaining_to_send; i++ ) { - *(g_rmt_objects[ch].remaining_ptr)++ = RMTMEM.chan[ch].data32[i].val; + *data++ = RMTMEM.chan[ch].data32[i].val; + } + // configured callback + if (g_rmt_objects[ch].cb) { + // actually received data ptr + uint32_t * data = g_rmt_objects[ch].remaining_ptr; + (g_rmt_objects[ch].cb)(data, _rmt_get_mem_len(ch)); + + // restart the reception + RMT.conf_ch[ch].conf1.mem_owner = 1; + RMT.conf_ch[ch].conf1.mem_wr_rst = 1; + RMT.conf_ch[ch].conf1.rx_en = 1; + RMT.int_ena.val |= _INT_RX_END(ch); + } else { + // if not callback provide, expect only one Rx + g_rmt_objects[ch].intr_mode &= ~e_rx_intr; } } - g_rmt_objects[ch].intr_mode &= ~e_rx_intr; - } else { // Report error and disable Rx interrupt - ets_printf("Unexpected Rx interrupt!\n"); + log_e("Unexpected Rx interrupt!\n"); // TODO: eplace messages with log_X RMT.int_ena.val &= ~_INT_RX_END(ch); } + + } if (intr_val&_INT_ERROR(ch)) { + digitalWrite(2, 1); // clear the flag - RMT.int_clr.val |= _INT_ERROR(ch); + RMT.int_clr.val = _INT_ERROR(ch); RMT.int_ena.val &= ~_INT_ERROR(ch); // report error - ets_printf("RMT Error %d!\n", ch); + log_e("RMT Error %d!\n", ch); if (g_rmt_objects[ch].events) { xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR); } - // reset memory RMT.conf_ch[ch].conf1.mem_rd_rst = 1; RMT.conf_ch[ch].conf1.mem_rd_rst = 0; @@ -579,17 +658,29 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val&_INT_TX_END(ch)) { - RMT.int_clr.val |= _INT_TX_END(ch); + RMT.int_clr.val = _INT_TX_END(ch); if (g_rmt_objects[ch].tx_state&e_last_data) { g_rmt_objects[ch].tx_state = e_end_trans; - ets_printf("Tx_End marked !\n"); RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + if (g_rmt_objects[ch].tx_state&e_first_half) { + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[i].val = 0; + g_rmt_objects[ch].tx_state &= ~e_first_half; + } else { + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[i].val = 0; + g_rmt_objects[ch].tx_state |= e_first_half; + } } else if (g_rmt_objects[ch].tx_state&e_end_trans) { - ets_printf("Tx completed !\n"); - // disable interrupts and clear states + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; RMT.int_ena.val &= ~_INT_TX_END(ch); RMT.int_ena.val &= ~_INT_THR_EVNT(ch); g_rmt_objects[ch].intr_mode = e_no_intr; @@ -599,7 +690,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val&_INT_THR_EVNT(ch)) { // clear the flag - RMT.int_clr.val |= _INT_THR_EVNT(ch); + RMT.int_clr.val | _INT_THR_EVNT(ch); // initial setup of continuous mode if (g_rmt_objects[ch].tx_state&e_set_conti) { @@ -635,9 +726,9 @@ static void IRAM_ATTR _rmt_isr(void* arg) g_rmt_objects[ch].remaining_ptr += half_tx_nr; } else { // less remaining data than buffer size -> fill in with fake (inactive) pulses - // ets_printf("last chunk..."); + ets_printf("last chunk..."); if (g_rmt_objects[ch].tx_state&e_first_half) { - // ets_printf("first\n"); + ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { if (i < remaining_size) { @@ -648,7 +739,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) } g_rmt_objects[ch].tx_state &= ~e_first_half; } else { - // ets_printf("second\n"); + ets_printf("second\n"); for (i = 0; i < half_tx_nr; i++) { if (i < remaining_size) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; @@ -666,27 +757,9 @@ static void IRAM_ATTR _rmt_isr(void* arg) // no data left, just copy the fake (inactive) pulses if ( (!(g_rmt_objects[ch].tx_state&e_last_data)) && (!(g_rmt_objects[ch].tx_state&e_end_trans)) ) { - // ets_printf("tail (empty)"); - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - int i; - if (g_rmt_objects[ch].tx_state&e_first_half) { - // ets_printf("...first\n"); - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i].val = 0x000F000F; - } - RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state &= ~e_first_half; - } else { - // ets_printf("...second\n"); - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; - } - RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state |= e_first_half; - } g_rmt_objects[ch].tx_state |= e_last_data; } else { - // ets_printf("do_nothing\n"); + // ...do_nothing } } } @@ -695,4 +768,20 @@ static void IRAM_ATTR _rmt_isr(void* arg) digitalWrite(2, 0); } +static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel) +{ + int block_num = RMT.conf_ch[channel].conf0.mem_size; + int item_block_len = block_num * 64; + volatile rmt_item32_t* data = RMTMEM.chan[channel].data32; + int idx; + for(idx = 0; idx < item_block_len; idx++) { + if(data[idx].duration0 == 0) { + return idx; + } else if(data[idx].duration1 == 0) { + return idx + 1; + } + } + return idx; +} + #endif /* MAIN_ESP32_HAL_RMT_H_ */ diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index d8461884b8f..dde72328cae 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -11,18 +11,32 @@ extern "C" { struct rmt_obj_s; typedef enum { - e_reserve_64_items = 1, - e_reserve_128_items = 2, - e_reserve_192_items = 3, - e_reserve_256_items = 4, - e_reserve_320_items = 5, - e_reserve_384_items = 6, - e_reserve_448_items = 7, - e_reserve_512_items = 8, + RMT_MEM_64 = 1, + RMT_MEM_128 = 2, + RMT_MEM_192 = 3, + RMT_MEM_256 = 4, + RMT_MEM_320 = 5, + RMT_MEM_384 = 6, + RMT_MEM_448 = 7, + RMT_MEM_512 = 8, } rmt_reserve_memsize_t; typedef struct rmt_obj_s rmt_obj_t; +typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len); + +typedef struct { + union { + struct { + uint32_t duration0 :15; + uint32_t level0 :1; + uint32_t duration1 :15; + uint32_t level1 :1; + }; + uint32_t val; + }; +} rmt_data_t; + /** * Initialize the object * @@ -40,13 +54,20 @@ float rmtSetTick(rmt_obj_t* rmt, float tick); * (more data being send while updating buffers in interrupts) * */ -bool rmtSend(rmt_obj_t* rmt, uint32_t* data, size_t size); +bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size); /** * Initiates async receive, event flag indicates data received * */ -bool rmtReceive(rmt_obj_t* rmt, uint32_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout); +bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout); + +/** +* Initiates async receive with automatic buffering +* and callback with data from ISR +* +*/ +bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb); /* Additional interface */ @@ -67,15 +88,24 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt); * Reads the data for particular channel * */ -bool rmtGetData(rmt_obj_t* rmt, uint32_t* data, size_t size); +bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size); /** * Setting threshold for Rx completed */ bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value); +/** + * Setting carrier + */ bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high); +/** + * Setting input filter + */ +bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) + + // TODO: // * uninstall interrupt when all channels are deinit // * send only-conti mode with circular-buffer diff --git a/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino b/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino index 1092287d674..2053bb3ea20 100644 --- a/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino +++ b/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino @@ -5,30 +5,32 @@ #include "esp32-hal-rmt.h" -uint32_t my_data[256]; - -uint32_t data[256]; +rmt_data_t my_data[256]; +rmt_data_t data[256]; rmt_obj_t* rmt_send = NULL; rmt_obj_t* rmt_recv = NULL; +static EventGroupHandle_t events; void setup() { - if ((rmt_send = rmtInit(18, true, 2, 1000)) == NULL) + Serial.begin(115200); + + if ((rmt_send = rmtInit(18, true, RMT_MEM_64)) == NULL) { - printf("init sender failed\n"); + Serial.println("init sender failed\n"); } - if ((rmt_recv = rmtInit(21, false, 2, 1000)) == NULL) + if ((rmt_recv = rmtInit(21, false, RMT_MEM_192)) == NULL) { - printf("init receiver failed\n"); + Serial.println("init receiver failed\n"); } float realTick = rmtSetTick(rmt_send, 400); - printf("real tick set to: %f\n", realTick); + Serial.printf("real tick set to: %f\n", realTick); realTick = rmtSetTick(rmt_recv, 400); - printf("real tick set to: %f\n", realTick); + Serial.printf("real tick set to: %f\n", realTick); events = xEventGroupCreate(); } @@ -38,15 +40,15 @@ void loop() // Init data int i; for (i=0; i<255; i++) { - data[i] = 0x80010001 + ((i%13)<<16) + 13-(i%13); + data[i].val = 0x80010001 + ((i%13)<<16) + 13-(i%13); } - data[255] = 0; + data[255].val = 0; // Start receiving - rmtReceiveAsync(rmt_recv, 0x4F, my_data, 60, events); + rmtReadAsync(rmt_recv, my_data, 100, events, false, 0); // Send in continous mode - rmtSendQueued(rmt_send, data, 56); + rmtWrite(rmt_send, data, 100); // Wait for data xEventGroupWaitBits(events, RMT_FLAG_RX_DONE, 1, 1, portMAX_DELAY); @@ -54,10 +56,10 @@ void loop() // Printout the received data plus the original values for (i=0; i<60; i++) { - printf("%08x=%08x ", my_data[i], data[i] ); - if (!((i+1)%4)) printf("\n"); + Serial.printf("%08x=%08x ", my_data[i], data[i] ); + if (!((i+1)%4)) Serial.println("\n"); } - printf("\n"); + Serial.println("\n"); delay(2000); } From 506ced89be3795ba721844fd26174c784300e545 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 2 Jul 2018 07:21:09 +0200 Subject: [PATCH 12/18] renamed internal structures and enums, fixed formatting --- cores/esp32/esp32-hal-rmt.c | 161 +++++++++--------- cores/esp32/esp32-hal-rmt.h | 4 +- .../{RMTLoopbakc.ino => RMTLoopback.ino} | 0 3 files changed, 85 insertions(+), 80 deletions(-) rename libraries/ESP32/examples/RMTLoopback/{RMTLoopbakc.ino => RMTLoopback.ino} (100%) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 48d8b58b810..7d452afe6b8 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -46,18 +46,18 @@ * Typedefs for internal stuctures, enums */ typedef enum { - e_no_intr = 0, - e_tx_intr = 1, - e_txthr_intr = 2, - e_rx_intr = 4, + E_NO_INTR = 0, + E_TX_INTR = 1, + E_TXTHR_INTR = 2, + E_RX_INTR = 4, } intr_mode_t; typedef enum { - e_inactive = 0, - e_first_half = 1, - e_last_data = 2, - e_end_trans = 4, - e_set_conti = 8, + E_INACTIVE = 0, + E_FIRST_HALF = 1, + E_LAST_DATA = 2, + E_END_TRANS = 4, + E_SET_CONTI = 8, } transaction_state_t; struct rmt_obj_s @@ -68,8 +68,8 @@ struct rmt_obj_s int channel; bool tx_not_rx; int buffers; - int remaining_to_send; - uint32_t* remaining_ptr; + int data_size; + uint32_t* data_ptr; intr_mode_t intr_mode; transaction_state_t tx_state; rmt_rx_data_cb_t cb; @@ -84,14 +84,14 @@ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = { }; static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = { - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, - { false, NULL, 0, 0, 0, 0, 0, NULL, e_no_intr, e_inactive, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, + { false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false}, }; /** @@ -187,6 +187,8 @@ bool rmtDeinit(rmt_obj_t *rmt) } size_t from = rmt->channel; + size_t to = rmt->buffers + rmt->channel; + size_t i; #if !CONFIG_DISABLE_HAL_LOCKS if(g_rmt_objlocks[from] != NULL) { @@ -194,12 +196,14 @@ bool rmtDeinit(rmt_obj_t *rmt) } #endif - size_t to = rmt->buffers + rmt->channel; - size_t i; + if (g_rmt_objects[from].data_alloc) { + free(g_rmt_objects[from].data_ptr); + } for (i = from; i < to; i++) { g_rmt_objects[i].allocated = false; } + g_rmt_objects[from].channel = 0; g_rmt_objects[from].buffers = 0; @@ -213,7 +217,7 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) } int channel = rmt->channel; - int allocated_size = 64 * rmt->buffers; + int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers; if (size > allocated_size) { @@ -224,10 +228,10 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle); } - rmt->remaining_to_send = size - MAX_DATA_PER_ITTERATION; - rmt->remaining_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION; - rmt->intr_mode = e_tx_intr | e_txthr_intr; - rmt->tx_state = e_set_conti | e_first_half; + rmt->data_size = size - MAX_DATA_PER_ITTERATION; + rmt->data_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION; + rmt->intr_mode = E_TX_INTR | E_TXTHR_INTR; + rmt->tx_state = E_SET_CONTI | E_FIRST_HALF; // init the tx limit for interruption RMT.tx_lim_ch[channel].limit = half_tx_nr; @@ -243,9 +247,9 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0; // clear and enable both Tx completed and half tx event - RMT.int_clr.val |= _INT_TX_END(channel); - RMT.int_clr.val |= _INT_THR_EVNT(channel); - RMT.int_clr.val |= _INT_ERROR(channel); + RMT.int_clr.val = _INT_TX_END(channel); + RMT.int_clr.val = _INT_THR_EVNT(channel); + RMT.int_clr.val = _INT_ERROR(channel); RMT.int_ena.val |= _INT_TX_END(channel); RMT.int_ena.val |= _INT_THR_EVNT(channel); @@ -261,7 +265,6 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) } } - bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size) { if (!rmt) { @@ -289,7 +292,7 @@ bool rmtBeginReceive(rmt_obj_t* rmt) } int channel = rmt->channel; - RMT.int_clr.val |= _INT_ERROR(channel); + RMT.int_clr.val = _INT_ERROR(channel); RMT.int_ena.val |= _INT_ERROR(channel); RMT.conf_ch[channel].conf1.mem_owner = 1; @@ -308,7 +311,7 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt) if (RMT.int_raw.val&_INT_RX_END(channel)) { // RX end flag - RMT.int_clr.val |= _INT_RX_END(channel); + RMT.int_clr.val = _INT_RX_END(channel); return true; } else { return false; @@ -323,13 +326,13 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb) int channel = rmt->channel; RMT_MUTEX_LOCK(channel); - rmt->intr_mode = e_rx_intr; - rmt->tx_state = e_first_half; + rmt->intr_mode = E_RX_INTR; + rmt->tx_state = E_FIRST_HALF; rmt->cb = cb; // allocate internally two buffers which would alternate if (!rmt->data_alloc) { - rmt->remaining_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t)); - rmt->remaining_to_send = MAX_DATA_PER_CHANNEL*rmt->buffers; + rmt->data_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t)); + rmt->data_size = MAX_DATA_PER_CHANNEL*rmt->buffers; rmt->data_alloc = true; } @@ -366,12 +369,12 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag } if (data && size>0) { - rmt->remaining_ptr = (uint32_t*)data; - rmt->remaining_to_send = size; + rmt->data_ptr = (uint32_t*)data; + rmt->data_size = size; } RMT_MUTEX_LOCK(channel); - rmt->intr_mode = e_rx_intr; + rmt->intr_mode = E_RX_INTR; RMT.conf_ch[channel].conf1.mem_owner = 1; @@ -596,28 +599,28 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMT.int_clr.val = _INT_RX_END(ch); // TODO: replace clear interrupts RMT.int_ena.val &= ~_INT_RX_END(ch); - if ((g_rmt_objects[ch].intr_mode)&e_rx_intr) { + if ((g_rmt_objects[ch].intr_mode) & E_RX_INTR) { if (g_rmt_objects[ch].events) { xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_RX_DONE); } - if (g_rmt_objects[ch].remaining_ptr && g_rmt_objects[ch].remaining_to_send > 0) { + if (g_rmt_objects[ch].data_ptr && g_rmt_objects[ch].data_size > 0) { size_t i; - uint32_t * data = g_rmt_objects[ch].remaining_ptr; + uint32_t * data = g_rmt_objects[ch].data_ptr; if (g_rmt_objects[ch].cb) { - if (g_rmt_objects[ch].tx_state&e_first_half) { - g_rmt_objects[ch].tx_state &= ~e_first_half; + if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; } else { - g_rmt_objects[ch].tx_state |= e_first_half; + g_rmt_objects[ch].tx_state |= E_FIRST_HALF; data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers); } } - for (i = 0; i < g_rmt_objects[ch].remaining_to_send; i++ ) { + for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) { *data++ = RMTMEM.chan[ch].data32[i].val; } // configured callback if (g_rmt_objects[ch].cb) { // actually received data ptr - uint32_t * data = g_rmt_objects[ch].remaining_ptr; + uint32_t * data = g_rmt_objects[ch].data_ptr; (g_rmt_objects[ch].cb)(data, _rmt_get_mem_len(ch)); // restart the reception @@ -627,7 +630,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMT.int_ena.val |= _INT_RX_END(ch); } else { // if not callback provide, expect only one Rx - g_rmt_objects[ch].intr_mode &= ~e_rx_intr; + g_rmt_objects[ch].intr_mode &= ~E_RX_INTR; } } } else { @@ -639,7 +642,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) } - if (intr_val&_INT_ERROR(ch)) { + if (intr_val & _INT_ERROR(ch)) { digitalWrite(2, 1); // clear the flag RMT.int_clr.val = _INT_ERROR(ch); @@ -656,79 +659,79 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMT.conf_ch[ch].conf1.mem_wr_rst = 0; } - if (intr_val&_INT_TX_END(ch)) { + if (intr_val & _INT_TX_END(ch)) { RMT.int_clr.val = _INT_TX_END(ch); - if (g_rmt_objects[ch].tx_state&e_last_data) { - g_rmt_objects[ch].tx_state = e_end_trans; + if (g_rmt_objects[ch].tx_state & E_LAST_DATA) { + g_rmt_objects[ch].tx_state = E_END_TRANS; RMT.conf_ch[ch].conf1.tx_conti_mode = 0; int half_tx_nr = MAX_DATA_PER_ITTERATION/2; int i; - if (g_rmt_objects[ch].tx_state&e_first_half) { + if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[i].val = 0x000F000F; } RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state &= ~e_first_half; + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; } else { for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; } RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state |= e_first_half; + g_rmt_objects[ch].tx_state |= E_FIRST_HALF; } - } else if (g_rmt_objects[ch].tx_state&e_end_trans) { + } else if (g_rmt_objects[ch].tx_state & E_END_TRANS) { RMT.conf_ch[ch].conf1.tx_conti_mode = 0; RMT.int_ena.val &= ~_INT_TX_END(ch); RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - g_rmt_objects[ch].intr_mode = e_no_intr; - g_rmt_objects[ch].tx_state = e_inactive; + g_rmt_objects[ch].intr_mode = E_NO_INTR; + g_rmt_objects[ch].tx_state = E_INACTIVE; } } - if (intr_val&_INT_THR_EVNT(ch)) { + if (intr_val & _INT_THR_EVNT(ch)) { // clear the flag - RMT.int_clr.val | _INT_THR_EVNT(ch); + RMT.int_clr.val = _INT_THR_EVNT(ch); // initial setup of continuous mode - if (g_rmt_objects[ch].tx_state&e_set_conti) { + if (g_rmt_objects[ch].tx_state & E_SET_CONTI) { RMT.conf_ch[ch].conf1.tx_conti_mode = 1; - g_rmt_objects[ch].intr_mode &= ~e_set_conti; + g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI; } // check if still any data to be sent - uint32_t* data = g_rmt_objects[ch].remaining_ptr; + uint32_t* data = g_rmt_objects[ch].data_ptr; if (data) { - int remaining_size = g_rmt_objects[ch].remaining_to_send; + int remaining_size = g_rmt_objects[ch].data_size; int half_tx_nr = MAX_DATA_PER_ITTERATION/2; int i; // will the remaining data occupy the entire halfbuffer if (remaining_size > half_tx_nr) { - if (g_rmt_objects[ch].tx_state&e_first_half) { + if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { // ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[i].val = data[i]; } - g_rmt_objects[ch].tx_state &= ~e_first_half; + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; } else { // ets_printf("second\n"); for (i = 0; i < half_tx_nr; i++) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; } - g_rmt_objects[ch].tx_state |= e_first_half; + g_rmt_objects[ch].tx_state |= E_FIRST_HALF; } - g_rmt_objects[ch].remaining_to_send -= half_tx_nr; - g_rmt_objects[ch].remaining_ptr += half_tx_nr; + g_rmt_objects[ch].data_size -= half_tx_nr; + g_rmt_objects[ch].data_ptr += half_tx_nr; } else { // less remaining data than buffer size -> fill in with fake (inactive) pulses - ets_printf("last chunk..."); - if (g_rmt_objects[ch].tx_state&e_first_half) { - ets_printf("first\n"); + //ets_printf("last chunk..."); + if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { + //ets_printf("first\n"); RMTMEM.chan[ch].data32[0].val = data[0] - 1; for (i = 1; i < half_tx_nr; i++) { if (i < remaining_size) { @@ -737,9 +740,9 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMTMEM.chan[ch].data32[i].val = 0x000F000F; } } - g_rmt_objects[ch].tx_state &= ~e_first_half; + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; } else { - ets_printf("second\n"); + //ets_printf("second\n"); for (i = 0; i < half_tx_nr; i++) { if (i < remaining_size) { RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; @@ -747,17 +750,17 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; } } - g_rmt_objects[ch].tx_state |= e_first_half; + g_rmt_objects[ch].tx_state |= E_FIRST_HALF; } RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; // mark - g_rmt_objects[ch].remaining_ptr = NULL; + g_rmt_objects[ch].data_ptr = NULL; } } else { // no data left, just copy the fake (inactive) pulses - if ( (!(g_rmt_objects[ch].tx_state&e_last_data)) && - (!(g_rmt_objects[ch].tx_state&e_end_trans)) ) { - g_rmt_objects[ch].tx_state |= e_last_data; + if ( (!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) && + (!(g_rmt_objects[ch].tx_state & E_END_TRANS)) ) { + g_rmt_objects[ch].tx_state |= E_END_TRANS; } else { // ...do_nothing } diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index dde72328cae..d46109e8bd3 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -103,7 +103,7 @@ bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t /** * Setting input filter */ -bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) +bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level); // TODO: @@ -112,6 +112,8 @@ bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level) // * put sanity checks to some macro or inlines // * doxy comments // * error reporting +// * release internal buffers +// * rename internal structures to make it more sensibles #ifdef __cplusplus } diff --git a/libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino b/libraries/ESP32/examples/RMTLoopback/RMTLoopback.ino similarity index 100% rename from libraries/ESP32/examples/RMTLoopback/RMTLoopbakc.ino rename to libraries/ESP32/examples/RMTLoopback/RMTLoopback.ino From 396ce23bb95b1c76e14e24f9a2a05025d0168b09 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 3 Jul 2018 11:59:44 +0200 Subject: [PATCH 13/18] cmake support for rmt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e0d89a796b..f9704e9d42c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(CORE_SRCS cores/esp32/esp32-hal-timer.c cores/esp32/esp32-hal-touch.c cores/esp32/esp32-hal-uart.c + cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp cores/esp32/HardwareSerial.cpp cores/esp32/IPAddress.cpp From fc391939d6d305a5e5a856658fd0e48437c88dd6 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 4 Jul 2018 09:03:24 +0200 Subject: [PATCH 14/18] refactored tx-conti interrupts to function to make it more readable --- cores/esp32/esp32-hal-rmt.c | 210 ++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 94 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 7d452afe6b8..94b0194a1b6 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -21,7 +21,7 @@ */ #define MAX_CHANNELS 8 #define MAX_DATA_PER_CHANNEL 64 -#define MAX_DATA_PER_ITTERATION 40 +#define MAX_DATA_PER_ITTERATION 62 #define _ABS(a) (a>0?a:-a) #define _LIMIT(a,b) (a>b?b:a) #define __INT_TX_END (1) @@ -42,6 +42,15 @@ # define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel]) #endif /* CONFIG_DISABLE_HAL_LOCKS */ +#define _RMT_INTERNAL_DEBUG +#ifdef _RMT_INTERNAL_DEBUG +# define DEBUG_INTERRUPT_START(pin) digitalWrite(pin, 1); +# define DEBUG_INTERRUPT_END(pin) digitalWrite(pin, 0); +#else +# define DEBUG_INTERRUPT_START(pin) +# define DEBUG_INTERRUPT_END(pin) +#endif /* _RMT_INTERNAL_DEBUG */ + /** * Typedefs for internal stuctures, enums */ @@ -118,6 +127,10 @@ static void _initPin(int pin, int channel, bool tx_not_rx); static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel); +static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch); + +static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch); + /** * Public method definitions @@ -234,7 +247,7 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size) rmt->tx_state = E_SET_CONTI | E_FIRST_HALF; // init the tx limit for interruption - RMT.tx_lim_ch[channel].limit = half_tx_nr; + RMT.tx_lim_ch[channel].limit = half_tx_nr+2; // reset memory pointer RMT.conf_ch[channel].conf1.apb_mem_rst = 1; RMT.conf_ch[channel].conf1.apb_mem_rst = 0; @@ -588,15 +601,13 @@ static void _initPin(int pin, int channel, bool tx_not_rx) static void IRAM_ATTR _rmt_isr(void* arg) { - digitalWrite(4, 1); - int intr_val = RMT.int_st.val; size_t ch; for (ch = 0; ch < MAX_CHANNELS; ch++) { if (intr_val & _INT_RX_END(ch)) { // clear the flag - RMT.int_clr.val = _INT_RX_END(ch); // TODO: replace clear interrupts + RMT.int_clr.val = _INT_RX_END(ch); RMT.int_ena.val &= ~_INT_RX_END(ch); if ((g_rmt_objects[ch].intr_mode) & E_RX_INTR) { @@ -606,6 +617,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (g_rmt_objects[ch].data_ptr && g_rmt_objects[ch].data_size > 0) { size_t i; uint32_t * data = g_rmt_objects[ch].data_ptr; + // in case of callback, provide switching between memories if (g_rmt_objects[ch].cb) { if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; @@ -617,7 +629,6 @@ static void IRAM_ATTR _rmt_isr(void* arg) for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) { *data++ = RMTMEM.chan[ch].data32[i].val; } - // configured callback if (g_rmt_objects[ch].cb) { // actually received data ptr uint32_t * data = g_rmt_objects[ch].data_ptr; @@ -662,33 +673,7 @@ static void IRAM_ATTR _rmt_isr(void* arg) if (intr_val & _INT_TX_END(ch)) { RMT.int_clr.val = _INT_TX_END(ch); - - if (g_rmt_objects[ch].tx_state & E_LAST_DATA) { - g_rmt_objects[ch].tx_state = E_END_TRANS; - RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - int i; - if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i].val = 0x000F000F; - } - RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; - } else { - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; - } - RMTMEM.chan[ch].data32[i].val = 0; - g_rmt_objects[ch].tx_state |= E_FIRST_HALF; - } - - } else if (g_rmt_objects[ch].tx_state & E_END_TRANS) { - RMT.conf_ch[ch].conf1.tx_conti_mode = 0; - RMT.int_ena.val &= ~_INT_TX_END(ch); - RMT.int_ena.val &= ~_INT_THR_EVNT(ch); - g_rmt_objects[ch].intr_mode = E_NO_INTR; - g_rmt_objects[ch].tx_state = E_INACTIVE; - } + _rmt_tx_mem_second(ch); } if (intr_val & _INT_THR_EVNT(ch)) { @@ -700,75 +685,112 @@ static void IRAM_ATTR _rmt_isr(void* arg) RMT.conf_ch[ch].conf1.tx_conti_mode = 1; g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI; } + _rmt_tx_mem_first(ch); + } + } +} - // check if still any data to be sent - uint32_t* data = g_rmt_objects[ch].data_ptr; - if (data) - { - int remaining_size = g_rmt_objects[ch].data_size; - int half_tx_nr = MAX_DATA_PER_ITTERATION/2; - int i; - - // will the remaining data occupy the entire halfbuffer - if (remaining_size > half_tx_nr) { - if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { - // ets_printf("first\n"); - RMTMEM.chan[ch].data32[0].val = data[0] - 1; - for (i = 1; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[i].val = data[i]; - } - g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; - } else { - // ets_printf("second\n"); - for (i = 0; i < half_tx_nr; i++) { - RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; - } - g_rmt_objects[ch].tx_state |= E_FIRST_HALF; - } - g_rmt_objects[ch].data_size -= half_tx_nr; - g_rmt_objects[ch].data_ptr += half_tx_nr; +static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch) +{ + DEBUG_INTERRUPT_START(4) + uint32_t* data = g_rmt_objects[ch].data_ptr; + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + + RMT.tx_lim_ch[ch].limit = half_tx_nr+2; + RMT.int_clr.val = _INT_THR_EVNT(ch); + RMT.int_ena.val |= _INT_THR_EVNT(ch); + + g_rmt_objects[ch].tx_state |= E_FIRST_HALF; + + if (data) { + int remaining_size = g_rmt_objects[ch].data_size; + // will the remaining data occupy the entire halfbuffer + if (remaining_size > half_tx_nr) { + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; + } + g_rmt_objects[ch].data_size -= half_tx_nr; + g_rmt_objects[ch].data_ptr += half_tx_nr; + } else { + for (i = 0; i < half_tx_nr; i++) { + if (i < remaining_size) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; } else { - // less remaining data than buffer size -> fill in with fake (inactive) pulses - //ets_printf("last chunk..."); - if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) { - //ets_printf("first\n"); - RMTMEM.chan[ch].data32[0].val = data[0] - 1; - for (i = 1; i < half_tx_nr; i++) { - if (i < remaining_size) { - RMTMEM.chan[ch].data32[i].val = data[i]; - } else { - RMTMEM.chan[ch].data32[i].val = 0x000F000F; - } - } - g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; - } else { - //ets_printf("second\n"); - for (i = 0; i < half_tx_nr; i++) { - if (i < remaining_size) { - RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i]; - } else { - RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; - } - } - g_rmt_objects[ch].tx_state |= E_FIRST_HALF; - } - RMTMEM.chan[ch].data32[MAX_DATA_PER_ITTERATION].val = 0; - // mark - g_rmt_objects[ch].data_ptr = NULL; + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; } - } else { - // no data left, just copy the fake (inactive) pulses - if ( (!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) && - (!(g_rmt_objects[ch].tx_state & E_END_TRANS)) ) { - g_rmt_objects[ch].tx_state |= E_END_TRANS; + } + g_rmt_objects[ch].data_ptr = NULL; + + } + } else if ((!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) && + (!(g_rmt_objects[ch].tx_state & E_END_TRANS))) { + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0; + g_rmt_objects[ch].tx_state |= E_LAST_DATA; + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + } else { + log_d("RMT Tx finished %d!\n", ch); + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; + RMT.int_ena.val &= ~_INT_TX_END(ch); + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + g_rmt_objects[ch].intr_mode = E_NO_INTR; + g_rmt_objects[ch].tx_state = E_INACTIVE; + } + DEBUG_INTERRUPT_END(4); +} + +static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch) +{ + DEBUG_INTERRUPT_START(2); + uint32_t* data = g_rmt_objects[ch].data_ptr; + int half_tx_nr = MAX_DATA_PER_ITTERATION/2; + int i; + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMT.tx_lim_ch[ch].limit = 0; + + if (data) { + int remaining_size = g_rmt_objects[ch].data_size; + + // will the remaining data occupy the entire halfbuffer + if (remaining_size > half_tx_nr) { + RMTMEM.chan[ch].data32[0].val = data[0] - 1; + for (i = 1; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = data[i]; + } + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; + // turn off the treshold interrupt + RMT.int_ena.val &= ~_INT_THR_EVNT(ch); + RMT.tx_lim_ch[ch].limit = 0; + g_rmt_objects[ch].data_size -= half_tx_nr; + g_rmt_objects[ch].data_ptr += half_tx_nr; + } else { + RMTMEM.chan[ch].data32[0].val = data[0] - 1; + for (i = 1; i < half_tx_nr; i++) { + if (i < remaining_size) { + RMTMEM.chan[ch].data32[i].val = data[i]; } else { - // ...do_nothing + RMTMEM.chan[ch].data32[i].val = 0x000F000F; } } + + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; + g_rmt_objects[ch].data_ptr = NULL; } + } else { + for (i = 0; i < half_tx_nr; i++) { + RMTMEM.chan[ch].data32[i].val = 0x000F000F; + } + RMTMEM.chan[ch].data32[i].val = 0; + + g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF; + RMT.tx_lim_ch[ch].limit = 0; + g_rmt_objects[ch].tx_state |= E_LAST_DATA; + RMT.conf_ch[ch].conf1.tx_conti_mode = 0; } - digitalWrite(4, 0); - digitalWrite(2, 0); + DEBUG_INTERRUPT_END(2); } static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel) From 8aa03e78b1d373db7ae4a54ddf55cd6f3eca9101 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 4 Jul 2018 15:10:58 +0200 Subject: [PATCH 15/18] added Tx and Rx examples --- .../RMTLoopback/RMTLoopbakc.ino} | 8 +- .../examples/RMT/RMTReadXJT/RMTReadXJT.ino | 172 ++++++++++++++++++ .../RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino | 84 +++++++++ 3 files changed, 258 insertions(+), 6 deletions(-) rename libraries/ESP32/examples/{RMTLoopback/RMTLoopback.ino => RMT/RMTLoopback/RMTLoopbakc.ino} (83%) create mode 100644 libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino create mode 100644 libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino diff --git a/libraries/ESP32/examples/RMTLoopback/RMTLoopback.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino similarity index 83% rename from libraries/ESP32/examples/RMTLoopback/RMTLoopback.ino rename to libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino index 2053bb3ea20..566a011eff8 100644 --- a/libraries/ESP32/examples/RMTLoopback/RMTLoopback.ino +++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino @@ -26,13 +26,9 @@ void setup() Serial.println("init receiver failed\n"); } + float realTick = rmtSetTick(rmt_send, 100); + printf("real tick set to: %fns\n", realTick); - float realTick = rmtSetTick(rmt_send, 400); - Serial.printf("real tick set to: %f\n", realTick); - realTick = rmtSetTick(rmt_recv, 400); - Serial.printf("real tick set to: %f\n", realTick); - - events = xEventGroupCreate(); } void loop() diff --git a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino new file mode 100644 index 00000000000..f058b27418d --- /dev/null +++ b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -0,0 +1,172 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "Arduino.h" + +#include "esp32-hal-rmt.h" + +#define XJT_VALID(i) (i->level0 && !i->level1 && i->duration0 >= 8 && i->duration0 <= 11) + + +rmt_obj_t* rmt_recv = NULL; + +static uint32_t *s_channels; + +static uint32_t channels[16]; +static uint8_t xjt_flags = 0x0; +static uint8_t xjt_rxid = 0x0; + + +typedef union { + struct { + uint8_t head;//0x7E + uint8_t rxid;//Receiver Number + uint8_t flags;//Range:0x20, Bind:0x01 + uint8_t reserved0;//0x00 + union { + struct { + uint8_t ch0_l; + uint8_t ch0_h:4; + uint8_t ch1_l:4; + uint8_t ch1_h; + }; + uint8_t bytes[3]; + } channels[4]; + uint8_t reserved1;//0x00 + uint8_t crc_h; + uint8_t crc_l; + uint8_t tail;//0x7E + }; + uint8_t buffer[20]; +} xjt_packet_t; + +static bool xjtReceiveBit(size_t index, bool bit){ + static xjt_packet_t xjt; + static uint8_t xjt_bit_index = 8; + static uint8_t xht_byte_index = 0; + static uint8_t xht_ones = 0; + + if(!index){ + xjt_bit_index = 8; + xht_byte_index = 0; + xht_ones = 0; + } + + if(xht_byte_index > 19){ + //fail! + return false; + } + if(bit){ + xht_ones++; + if(xht_ones > 5 && xht_byte_index && xht_byte_index < 19){ + //fail! + return false; + } + //add bit + xjt.buffer[xht_byte_index] |= (1 << --xjt_bit_index); + } else if(xht_ones == 5 && xht_byte_index && xht_byte_index < 19){ + xht_ones = 0; + //skip bit + return true; + } else { + xht_ones = 0; + //add bit + xjt.buffer[xht_byte_index] &= ~(1 << --xjt_bit_index); + } + if ((!xjt_bit_index) || (xjt_bit_index==1 && xht_byte_index==19) ) { + xjt_bit_index = 8; + if(!xht_byte_index && xjt.buffer[0] != 0x7E){ + //fail! + return false; + } + xht_byte_index++; + if(xht_byte_index == 20){ + //done + if(xjt.buffer[19] != 0x7E){ + //fail! + return false; + } + //check crc? + + xjt_flags = xjt.flags; + xjt_rxid = xjt.rxid; + for(int i=0; i<4; i++){ + uint16_t ch0 = xjt.channels[i].ch0_l | ((uint16_t)(xjt.channels[i].ch0_h & 0x7) << 8); + ch0 = ((ch0 * 2) + 2452) / 3; + uint16_t ch1 = xjt.channels[i].ch1_l | ((uint16_t)(xjt.channels[i].ch1_h & 0x7F) << 4); + ch1 = ((ch1 * 2) + 2452) / 3; + uint8_t c0n = i*2; + if(xjt.channels[i].ch0_h & 0x8){ + c0n += 8; + } + uint8_t c1n = i*2+1; + if(xjt.channels[i].ch1_h & 0x80){ + c1n += 8; + } + s_channels[c0n] = ch0; + s_channels[c1n] = ch1; + } + } + } + return true; +} + +void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){ + size_t chan = 0; + bool valid = false; + rmt_data_t* it = NULL; + + if (!channels) { + log_e("Please provide data block for storing channel info"); + return; + } + s_channels = channels; + + valid = false; + it = &items[0]; + for(size_t i = 0; iduration1 >= 5 && it->duration1 <= 8){ + valid = xjtReceiveBit(i, false); + } else if(it->duration1 >= 13 && it->duration1 <= 16){ + valid = xjtReceiveBit(i, true); + } else { + valid = false; + } + } + } +} + +extern "C" void receive_data(uint32_t *data, size_t len) +{ + parseRmt((rmt_data_t*) data, len, channels); +} + +void setup() +{ + Serial.begin(115200); + + // Initialize the channel to capture up to 192 items + if ((rmt_recv = rmtInit(21, false, RMT_MEM_192)) == NULL) + { + Serial.println("init receiver failed\n"); + } + + // Setup 1us tick + float realTick = rmtSetTick(rmt_recv, 1000); + printf("real tick set to: %fns\n", realTick); + + // Ask to start reading + rmtRead(rmt_recv, receive_data); +} + +void loop() +{ + // printout some of the channels + Serial.printf("%04x %04x %04x %04x\n", channels[0], channels[1], channels[2], channels[3]); + delay(500); +} diff --git a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino new file mode 100644 index 00000000000..293b8d36913 --- /dev/null +++ b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino @@ -0,0 +1,84 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "Arduino.h" + +#include "esp32-hal-rmt.h" + +#define LED_MATRIX_SIZE 8*4*24 + +// +// Note: This example uses Neopixel LED board, 32 LEDs chained one +// after another, each RGB LED has its 24 bit value +// for color configuration (8b for each color) +// +// Bits encoded as pulses as follows: +// +// "0": +// ---+ +--------------+ +// | | | +// | | | +// | | | +// | | | +// +-------+ +-- +// | 0.4us | 0.85 0us | +// +// "1": +// ---+ +-------+ +// | | | +// | | | +// | | | +// | | | +// +-------------+ +-- +// | 0.8us | 0.4us | + +rmt_data_t led_data[LED_MATRIX_SIZE]; + +rmt_obj_t* rmt_send = NULL; + +static EventGroupHandle_t events; + +void setup() +{ + Serial.begin(115200); + + if ((rmt_send = rmtInit(18, true, RMT_MEM_64)) == NULL) + { + Serial.println("init sender failed\n"); + } + + float realTick = rmtSetTick(rmt_send, 100); + Serial.printf("real tick set to: %fns\n", realTick); + +} + +int color[] = { 0x55, 0x11, 0x77 }; // RGB value +int led_index = 0; + +void loop() +{ + // Init data with only one led ON + int i; + int item, bit, inx; + for (i=0; i=LED_MATRIX_SIZE) { + led_index = 0; + } + + // Send the data + rmtWrite(rmt_send, led_data, LED_MATRIX_SIZE); + + delay(100); +} From 1cb7560ba68b997a146924bbb1afca465be98cae Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 4 Jul 2018 16:50:21 +0200 Subject: [PATCH 16/18] added license headers --- cores/esp32/esp32-hal-rmt.c | 17 +++-- cores/esp32/esp32-hal-rmt.h | 23 ++++++- cores/esp32/esp32-hal.h | 1 + .../examples/RMT/RMTLoopback/RMTLoopbakc.ino | 2 +- .../examples/RMT/RMTReadXJT/RMTReadXJT.ino | 66 ++++++++++++++----- .../RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino | 4 +- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/cores/esp32/esp32-hal-rmt.c b/cores/esp32/esp32-hal-rmt.c index 94b0194a1b6..d46caf833b1 100644 --- a/cores/esp32/esp32-hal-rmt.c +++ b/cores/esp32/esp32-hal-rmt.c @@ -1,5 +1,16 @@ -#ifndef MAIN_ESP32_HAL_RMT_H_ -#define MAIN_ESP32_HAL_RMT_H_ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" @@ -808,5 +819,3 @@ static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel) } return idx; } - -#endif /* MAIN_ESP32_HAL_RMT_H_ */ diff --git a/cores/esp32/esp32-hal-rmt.h b/cores/esp32/esp32-hal-rmt.h index d46109e8bd3..944178e31ec 100644 --- a/cores/esp32/esp32-hal-rmt.h +++ b/cores/esp32/esp32-hal-rmt.h @@ -1,3 +1,20 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MAIN_ESP32_HAL_RMT_H_ +#define MAIN_ESP32_HAL_RMT_H_ + #ifdef __cplusplus extern "C" { #endif @@ -112,9 +129,9 @@ bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level); // * put sanity checks to some macro or inlines // * doxy comments // * error reporting -// * release internal buffers -// * rename internal structures to make it more sensibles #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* MAIN_ESP32_HAL_RMT_H_ */ diff --git a/cores/esp32/esp32-hal.h b/cores/esp32/esp32-hal.h index 3b19b052fbb..df4adf960d8 100644 --- a/cores/esp32/esp32-hal.h +++ b/cores/esp32/esp32-hal.h @@ -56,6 +56,7 @@ void yield(void); #include "esp32-hal-spi.h" #include "esp32-hal-i2c.h" #include "esp32-hal-ledc.h" +#include "esp32-hal-rmt.h" #include "esp32-hal-sigmadelta.h" #include "esp32-hal-timer.h" #include "esp32-hal-bt.h" diff --git a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino index 566a011eff8..bdffff47067 100644 --- a/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino +++ b/libraries/ESP32/examples/RMT/RMTLoopback/RMTLoopbakc.ino @@ -3,7 +3,7 @@ #include "freertos/event_groups.h" #include "Arduino.h" -#include "esp32-hal-rmt.h" +#include "esp32-hal.h" rmt_data_t my_data[256]; rmt_data_t data[256]; diff --git a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino index f058b27418d..e2e059fdfc9 100644 --- a/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino +++ b/libraries/ESP32/examples/RMT/RMTReadXJT/RMTReadXJT.ino @@ -3,20 +3,40 @@ #include "freertos/event_groups.h" #include "Arduino.h" -#include "esp32-hal-rmt.h" - -#define XJT_VALID(i) (i->level0 && !i->level1 && i->duration0 >= 8 && i->duration0 <= 11) - - -rmt_obj_t* rmt_recv = NULL; - -static uint32_t *s_channels; - -static uint32_t channels[16]; -static uint8_t xjt_flags = 0x0; -static uint8_t xjt_rxid = 0x0; - - +#include "esp32-hal.h" + +// +// Note: This example uses a FrSKY device communication +// using XJT D12 protocol +// +// ; 0 bit = 6us low/10us high +// ; 1 bit = 14us low/10us high +// ; +// ; --------+ +----------+ +----------+ +// ; | | | | | +// ; | 0 | | 1 | | +// ; | | | | | +// ; | | | | | +// ; +-------+ +-----------------+ +--------- +// ; +// ; | 6us 10us | 14us 10us | +// ; |-------|----------|-----------------|----------|-------- +// ; | 16us | 24us | + +// Typedef of received frame +// +// ; 0x00 - Sync, 0x7E (sync header ID) +// ; 0x01 - Rx ID, 0x?? (receiver ID number, 0x00-0x??) +// ; 0x02 - Flags 1, 0x?? (used for failsafe and binding) +// ; 0x03 - Flags 2, 0x00 (reserved) +// ; 0x04-0x06, Channels 1/9 and 2/10 +// ; 0x07-0x09, Channels 3/11 and 4/12 +// ; 0x0A-0x0C, Channels 5/13 and 6/14 +// ; 0x0D-0x0F, Channels 7/15 and 8/16 +// ; 0x10 - 0x00, always zero +// ; 0x11 - CRC-16 High +// ; 0x12 - CRC-16 Low +// ; 0x13 - Tail, 0x7E (tail ID) typedef union { struct { uint8_t head;//0x7E @@ -40,6 +60,15 @@ typedef union { uint8_t buffer[20]; } xjt_packet_t; +#define XJT_VALID(i) (i->level0 && !i->level1 && i->duration0 >= 8 && i->duration0 <= 11) + +rmt_obj_t* rmt_recv = NULL; + +static uint32_t *s_channels; +static uint32_t channels[16]; +static uint8_t xjt_flags = 0x0; +static uint8_t xjt_rxid = 0x0; + static bool xjtReceiveBit(size_t index, bool bit){ static xjt_packet_t xjt; static uint8_t xjt_bit_index = 8; @@ -113,7 +142,7 @@ static bool xjtReceiveBit(size_t index, bool bit){ void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){ size_t chan = 0; - bool valid = false; + bool valid = true; rmt_data_t* it = NULL; if (!channels) { @@ -122,9 +151,9 @@ void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){ } s_channels = channels; - valid = false; it = &items[0]; for(size_t i = 0; iduration1 && !it->level1 && it->duration0 >= 5 && it->duration0 <= 8) { + valid = xjtReceiveBit(i, false); + } } } @@ -158,7 +190,7 @@ void setup() // Setup 1us tick float realTick = rmtSetTick(rmt_recv, 1000); - printf("real tick set to: %fns\n", realTick); + Serial.printf("real tick set to: %fns\n", realTick); // Ask to start reading rmtRead(rmt_recv, receive_data); diff --git a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino index 293b8d36913..36b303edcf6 100644 --- a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino +++ b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino @@ -3,7 +3,7 @@ #include "freertos/event_groups.h" #include "Arduino.h" -#include "esp32-hal-rmt.h" +#include "esp32-hal.h" #define LED_MATRIX_SIZE 8*4*24 @@ -73,7 +73,7 @@ void loop() led_data[i].val = 0x80040008; } // make the led travel in the pannel - if ((++led_index)>=LED_MATRIX_SIZE) { + if ((++led_index)>=4*8) { led_index = 0; } From ab4ffbc05fb356edf4094044a687f58ad88843e6 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 4 Jul 2018 18:04:05 +0200 Subject: [PATCH 17/18] minor updates per review --- .../RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino index 36b303edcf6..77bca46fdb6 100644 --- a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino +++ b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino @@ -5,7 +5,8 @@ #include "esp32-hal.h" -#define LED_MATRIX_SIZE 8*4*24 +#define NR_OF_LEDS 8*4 +#define NR_OF_PIXELS 24*NR_OF_LEDS // // Note: This example uses Neopixel LED board, 32 LEDs chained one @@ -32,12 +33,10 @@ // +-------------+ +-- // | 0.8us | 0.4us | -rmt_data_t led_data[LED_MATRIX_SIZE]; +rmt_data_t led_data[NR_OF_PIXELS]; rmt_obj_t* rmt_send = NULL; -static EventGroupHandle_t events; - void setup() { Serial.begin(115200); @@ -58,27 +57,27 @@ int led_index = 0; void loop() { // Init data with only one led ON - int i; - int item, bit, inx; - for (i=0; i=4*8) { + if ((++led_index)>=NR_OF_LEDS) { led_index = 0; } // Send the data - rmtWrite(rmt_send, led_data, LED_MATRIX_SIZE); + rmtWrite(rmt_send, led_data, NR_OF_PIXELS); delay(100); } From 8d727501f67cb59860b83499ab9280bbf95e2856 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Thu, 26 Jul 2018 08:26:14 +0200 Subject: [PATCH 18/18] used struct access, renamed defines, corrected diagram --- .../RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino index 77bca46fdb6..8a880abdd18 100644 --- a/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino +++ b/libraries/ESP32/examples/RMT/RMTWriteNeoPixel/RMTWriteNeoPixel.ino @@ -6,7 +6,7 @@ #include "esp32-hal.h" #define NR_OF_LEDS 8*4 -#define NR_OF_PIXELS 24*NR_OF_LEDS +#define NR_OF_ALL_BITS 24*NR_OF_LEDS // // Note: This example uses Neopixel LED board, 32 LEDs chained one @@ -16,24 +16,24 @@ // Bits encoded as pulses as follows: // // "0": -// ---+ +--------------+ -// | | | +// +-------+ +-- // | | | // | | | // | | | -// +-------+ +-- +// ---| |--------------| +// + + + // | 0.4us | 0.85 0us | // // "1": -// ---+ +-------+ +// +-------------+ +-- // | | | // | | | // | | | // | | | -// +-------------+ +-- +// ---+ +-------+ // | 0.8us | 0.4us | -rmt_data_t led_data[NR_OF_PIXELS]; +rmt_data_t led_data[NR_OF_ALL_BITS]; rmt_obj_t* rmt_send = NULL; @@ -63,9 +63,15 @@ void loop() for (col=0; col<3; col++ ) { for (bit=0; bit<8; bit++){ if ( (color[col] & (1<<(8-bit))) && (led == led_index) ) { - led_data[i].val = 0x80070006; + led_data[i].level0 = 1; + led_data[i].duration0 = 8; + led_data[i].level1 = 0; + led_data[i].duration1 = 4; } else { - led_data[i].val = 0x80040008; + led_data[i].level0 = 1; + led_data[i].duration0 = 4; + led_data[i].level1 = 0; + led_data[i].duration1 = 8; } i++; } @@ -77,7 +83,7 @@ void loop() } // Send the data - rmtWrite(rmt_send, led_data, NR_OF_PIXELS); + rmtWrite(rmt_send, led_data, NR_OF_ALL_BITS); delay(100); }