├── README.md ├── esp32_rmt.cpp ├── esp32_rmt.h ├── nec.cpp ├── rc5_rc6.cpp ├── rmt.c ├── rmt.h └── test_codes ├── intex_it_500b.csv └── tatsky.csv /README.md: -------------------------------------------------------------------------------- 1 | Library to encode and decode IR Remote signals using the built in Remote peripheral of the ESP32 chip. 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /esp32_rmt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "esp32_rmt.h" 5 | 6 | #define TRANSMIT 1 7 | #define RECEIVE 0 8 | 9 | #if RMT_RX_SELF_TEST 10 | #define RMT_RX_ACTIVE_LEVEL 0 /*!< Data bit is active high for self test mode */ 11 | #define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */ 12 | #else 13 | //Test with infrared LED, we have to enable carrier for transmitter 14 | //When testing via IR led, the receiver waveform is usually active-low. 15 | #define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */ 16 | #define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */ 17 | #endif 18 | 19 | 20 | ESP32_RMT::ESP32_RMT() 21 | { 22 | //printf("booting remote peripheral\n\r"); 23 | //printf("hello world\n\r"); 24 | } 25 | 26 | void ESP32_RMT::begin(uint8_t pin, bool mode) 27 | { 28 | if(mode==TRANSMIT) 29 | { 30 | 31 | txPin = pin; 32 | 33 | } 34 | } 35 | 36 | 37 | 38 | 39 | 40 | void ESP32_RMT::rmt_tx_init() 41 | { 42 | 43 | } 44 | 45 | 46 | 47 | 48 | void ESP32_RMT::send(uint8_t data) 49 | { 50 | 51 | 52 | 53 | 54 | int channel = (rmt_channel_t)RMT_TX_CHANNEL; 55 | 56 | int nec_tx_num = RMT_TX_DATA_NUM; 57 | for(;;) { 58 | //ESP_LOGI(NEC_TAG, "RMT TX DATA"); 59 | size_t size = (sizeof(rmt_item32_t) * 1); 60 | //each item represent a cycle of waveform. 61 | rmt_item32_t* item = (rmt_item32_t*) malloc(size); 62 | 63 | item->level0 = 1; 64 | item->duration0 = (9000) / 10 * RMT_TICK_10_US; 65 | item->level1 = 0; 66 | item->duration1 = (4500) / 10 * RMT_TICK_10_US; 67 | 68 | 69 | //printf("writing items\n\r"); 70 | rmt_write_items((rmt_channel_t)channel, item, 2, true); 71 | //Wait until sending is done. 72 | rmt_wait_tx_done((rmt_channel_t)channel); 73 | //before we free the data, make sure sending is already done. 74 | free(item); 75 | } 76 | 77 | } 78 | 79 | -------------------------------------------------------------------------------- /esp32_rmt.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "driver/rmt.h" 3 | 4 | 5 | #ifndef ESP32_RMT_H 6 | #define ESP32_RMT_H 7 | 8 | 9 | #define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */ 10 | #define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */ 11 | #define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */ 12 | #define RMT_INTR_NUM 19 /*!< RMT interrupt number, select from soc.h */ 13 | #define RMT_CLK_DIV 100 /*!< RMT counter clock divider */ 14 | #define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter */ 15 | 16 | #define RMT_TX_DATA_NUM 1 /*!< NEC tx test data number */ 17 | #define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */ 18 | 19 | 20 | 21 | class ESP32_RMT 22 | { 23 | public: 24 | ESP32_RMT(); //reserved for future use 25 | void begin(uint8_t, bool); 26 | 27 | //transmit functions 28 | void sendRaw (const uint8_t[], uint8_t, uint8_t); 29 | void send(uint8_t); 30 | 31 | void necSend(uint16_t, uint16_t); 32 | 33 | private: 34 | void rmt_tx_init(); 35 | void nec_fill_item_level(rmt_item32_t* ,int ,int); 36 | void nec_fill_item_header(rmt_item32_t* ); 37 | void nec_fill_item_bit_one(rmt_item32_t* ); 38 | void nec_fill_item_bit_zero(rmt_item32_t*); 39 | void nec_fill_item_end(rmt_item32_t* ); 40 | int nec_build_items(int , rmt_item32_t* , int , uint16_t , uint16_t); 41 | 42 | uint8_t txChannel = 1; 43 | uint8_t rxChannel = 0; 44 | 45 | uint8_t txPin = 16; //default transmit pin 46 | uint8_t rxPin = 19; //default receive pin 47 | 48 | 49 | }; 50 | 51 | 52 | 53 | #endif // ESP32_RMT 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /nec.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "freertos/FreeRTOS.h" 5 | #include "freertos/task.h" 6 | #include "esp_system.h" 7 | #include "nvs_flash.h" 8 | #include "driver/periph_ctrl.h" 9 | 10 | #include "freertos/queue.h" 11 | #include "nvs_flash.h" 12 | 13 | #include "esp32_rmt.h" 14 | 15 | #define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */ 16 | #define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/ 17 | #define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */ 18 | #define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */ 19 | #define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */ 20 | #define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */ 21 | #define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */ 22 | #define NEC_BIT_MARGIN 150 /*!< NEC parse margin time */ 23 | 24 | #define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */ 25 | #define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */ 26 | 27 | #define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */ 28 | 29 | #define RMT_TX_CARRIER_EN 1 30 | 31 | #define NEC_FREQ 38000 32 | 33 | //send 1 frame of NEC data. 34 | 35 | void ESP32_RMT::necSend(uint16_t addr, uint16_t cmd) 36 | { 37 | rmt_config_t rmt_tx; 38 | rmt_tx.channel = (rmt_channel_t)txChannel; 39 | rmt_tx.gpio_num =(gpio_num_t) txPin; 40 | rmt_tx.mem_block_num = 1; 41 | rmt_tx.clk_div = RMT_CLK_DIV; 42 | rmt_tx.tx_config.loop_en = false; 43 | rmt_tx.tx_config.carrier_duty_percent = 50; 44 | rmt_tx.tx_config.carrier_freq_hz = NEC_FREQ; 45 | rmt_tx.tx_config.carrier_level = (rmt_carrier_level_t)1; 46 | rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN; 47 | rmt_tx.tx_config.idle_level = (rmt_idle_level_t)0; 48 | rmt_tx.tx_config.idle_output_en = true; 49 | rmt_tx.rmt_mode = (rmt_mode_t)0; 50 | rmt_config(&rmt_tx); 51 | rmt_driver_install(rmt_tx.channel, 0, RMT_INTR_NUM); 52 | 53 | //printf("cmd: %d, data: %d \n\r ", cmd, addr); 54 | int channel = RMT_TX_CHANNEL; 55 | int nec_tx_num = RMT_TX_DATA_NUM; 56 | 57 | // ESP_LOGI(NEC_TAG, "RMT TX DATA"); 58 | size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num); 59 | //each item represent a cycle of waveform. 60 | rmt_item32_t* item = (rmt_item32_t*) malloc(size); 61 | int item_num = NEC_DATA_ITEM_NUM * nec_tx_num; 62 | //printf("item_num:%d \n\r", item_num); 63 | memset((void*) item, 0, size); 64 | int i, offset = 0; 65 | while(1) { 66 | //To build a series of waveforms. 67 | i = nec_build_items((rmt_channel_t)channel, item + offset, item_num - offset, addr, cmd); 68 | if(i < 0) { 69 | break; 70 | } 71 | cmd++; 72 | addr++; 73 | offset += i; 74 | } 75 | //To send data according to the waveform items. 76 | rmt_write_items((rmt_channel_t)channel, item, item_num, true); 77 | //Wait until sending is done. 78 | rmt_wait_tx_done((rmt_channel_t)channel); 79 | //before we free the data, make sure sending is already done. 80 | free(item); 81 | 82 | } 83 | 84 | /* 85 | * @brief Build register value of waveform for NEC one data bit 86 | */ 87 | inline void ESP32_RMT::nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us) 88 | { 89 | item->level0 = 1; 90 | item->duration0 = (high_us) / 10 * RMT_TICK_10_US; 91 | item->level1 = 0; 92 | item->duration1 = (low_us) / 10 * RMT_TICK_10_US; 93 | } 94 | 95 | /* 96 | * @brief Generate NEC header value: active 9ms + negative 4.5ms 97 | */ 98 | void ESP32_RMT::nec_fill_item_header(rmt_item32_t* item) 99 | { 100 | nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US); 101 | } 102 | 103 | /* 104 | * @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms 105 | */ 106 | void ESP32_RMT::nec_fill_item_bit_one(rmt_item32_t* item) 107 | { 108 | nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US); 109 | } 110 | 111 | /* 112 | * @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms 113 | */ 114 | void ESP32_RMT::nec_fill_item_bit_zero(rmt_item32_t* item) 115 | { 116 | nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US); 117 | } 118 | 119 | /* 120 | * @brief Generate NEC end signal: positive 0.56ms 121 | */ 122 | void ESP32_RMT::nec_fill_item_end(rmt_item32_t* item) 123 | { 124 | nec_fill_item_level(item, NEC_BIT_END, 0x7fff); 125 | } 126 | 127 | 128 | int ESP32_RMT::nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data) 129 | { 130 | int i = 0, j = 0; 131 | if(item_num < NEC_DATA_ITEM_NUM) { 132 | return -1; 133 | } 134 | nec_fill_item_header(item++); 135 | i++; 136 | for(j = 0; j < 16; j++) { 137 | if(addr & 0x1) { 138 | nec_fill_item_bit_one(item); 139 | } else { 140 | nec_fill_item_bit_zero(item); 141 | } 142 | item++; 143 | i++; 144 | addr >>= 1; 145 | } 146 | for(j = 0; j < 16; j++) { 147 | if(cmd_data & 0x1) { 148 | nec_fill_item_bit_one(item); 149 | } else { 150 | nec_fill_item_bit_zero(item); 151 | } 152 | item++; 153 | i++; 154 | cmd_data >>= 1; 155 | } 156 | nec_fill_item_end(item); 157 | i++; 158 | return i; 159 | } -------------------------------------------------------------------------------- /rc5_rc6.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExploreEmbedded/ESP32_RMT/241388f607cf59074c5644e0edb48e4f9c21207f/rc5_rc6.cpp -------------------------------------------------------------------------------- /rmt.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include 15 | #include 16 | #include 17 | #include "freertos/FreeRTOS.h" 18 | #include "freertos/semphr.h" 19 | #include "freertos/xtensa_api.h" 20 | #include "freertos/ringbuf.h" 21 | #include "esp_intr.h" 22 | #include "esp_log.h" 23 | #include "esp_err.h" 24 | #include "soc/gpio_sig_map.h" 25 | #include "soc/rmt_struct.h" 26 | #include "driver/periph_ctrl.h" 27 | #include "rmt.h" 28 | #include 29 | 30 | #define RMT_SOUCCE_CLK_APB (APB_CLK_FREQ) /*!< RMT source clock is APB_CLK */ 31 | #define RMT_SOURCE_CLK_REF (1 * 1000000) /*!< not used yet */ 32 | #define RMT_SOURCE_CLK(select) ((select == RMT_BASECLK_REF) ? (RMT_SOURCE_CLK_REF) : (RMT_SOUCCE_CLK_APB)) /*! RMT source clock frequency */ 33 | 34 | #define RMT_CHANNEL_ERROR_STR "RMT CHANNEL ERR" 35 | #define RMT_ADDR_ERROR_STR "RMT ADDRESS ERR" 36 | #define RMT_MEM_CNT_ERROR_STR "RMT MEM BLOCK NUM ERR" 37 | #define RMT_CARRIER_ERROR_STR "RMT CARRIER LEVEL ERR" 38 | #define RMT_MEM_OWNER_ERROR_STR "RMT MEM OWNER_ERR" 39 | #define RMT_BASECLK_ERROR_STR "RMT BASECLK ERR" 40 | #define RMT_WR_MEM_OVF_ERROR_STR "RMT WR MEM OVERFLOW" 41 | #define RMT_GPIO_ERROR_STR "RMT GPIO ERROR" 42 | #define RMT_MODE_ERROR_STR "RMT MODE ERROR" 43 | #define RMT_CLK_DIV_ERROR_STR "RMT CLK DIV ERR" 44 | #define RMT_DRIVER_ERROR_STR "RMT DRIVER ERR" 45 | #define RMT_DRIVER_LENGTH_ERROR_STR "RMT PARAM LEN ERROR" 46 | 47 | #define tNEC_ITEM_DURATION(d) ((d & 0x7fff)*10/tRMT_TICK_10_US) 48 | #define tRMT_TICK_10_US (80000000/100/100000) 49 | static const char* RMT_TAG = "RMT"; 50 | static bool s_rmt_driver_installed = false; 51 | 52 | #define RMT_CHECK(a, str, ret) if (!(a)) { \ 53 | ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \ 54 | return (ret); \ 55 | } 56 | static portMUX_TYPE rmt_spinlock = portMUX_INITIALIZER_UNLOCKED; 57 | 58 | typedef struct { 59 | int tx_offset; 60 | int tx_len_rem; 61 | int tx_sub_len; 62 | rmt_channel_t channel; 63 | rmt_item32_t* tx_data; 64 | xSemaphoreHandle tx_sem; 65 | RingbufHandle_t tx_buf; 66 | RingbufHandle_t rx_buf; 67 | } rmt_obj_t; 68 | 69 | rmt_obj_t* p_rmt_obj[RMT_CHANNEL_MAX] = {0}; 70 | 71 | static void rmt_set_tx_wrap_en(rmt_channel_t channel, bool en) 72 | { 73 | portENTER_CRITICAL(&rmt_spinlock); 74 | RMT.apb_conf.mem_tx_wrap_en = en; 75 | portEXIT_CRITICAL(&rmt_spinlock); 76 | } 77 | 78 | static void rmt_set_data_mode(rmt_data_mode_t data_mode) 79 | { 80 | portENTER_CRITICAL(&rmt_spinlock); 81 | RMT.apb_conf.fifo_mask = data_mode; 82 | portEXIT_CRITICAL(&rmt_spinlock); 83 | } 84 | 85 | esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt) 86 | { 87 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 88 | RMT.conf_ch[channel].conf0.div_cnt = div_cnt; 89 | return ESP_OK; 90 | } 91 | 92 | esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t* div_cnt) 93 | { 94 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 95 | RMT_CHECK(div_cnt != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 96 | *div_cnt = RMT.conf_ch[channel].conf0.div_cnt; 97 | return ESP_OK; 98 | } 99 | 100 | esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh) 101 | { 102 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 103 | RMT.conf_ch[channel].conf0.idle_thres = thresh; 104 | return ESP_OK; 105 | } 106 | 107 | esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh) 108 | { 109 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 110 | RMT_CHECK(thresh != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 111 | *thresh = RMT.conf_ch[channel].conf0.idle_thres; 112 | return ESP_OK; 113 | } 114 | 115 | esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num) 116 | { 117 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 118 | RMT_CHECK(rmt_mem_num < 16, RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG); 119 | RMT.conf_ch[channel].conf0.mem_size = rmt_mem_num; 120 | return ESP_OK; 121 | } 122 | 123 | esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num) 124 | { 125 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 126 | RMT_CHECK(rmt_mem_num != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 127 | *rmt_mem_num = RMT.conf_ch[channel].conf0.mem_size; 128 | return ESP_OK; 129 | } 130 | 131 | esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t high_level, uint16_t low_level, 132 | rmt_carrier_level_t carrier_level) 133 | { 134 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 135 | RMT_CHECK(carrier_level < RMT_CARRIER_LEVEL_MAX, RMT_CARRIER_ERROR_STR, ESP_ERR_INVALID_ARG); 136 | RMT.carrier_duty_ch[channel].high = high_level; 137 | RMT.carrier_duty_ch[channel].low = low_level; 138 | RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level; 139 | RMT.conf_ch[channel].conf0.carrier_en = carrier_en; 140 | return ESP_OK; 141 | } 142 | 143 | esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en) 144 | { 145 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 146 | RMT.conf_ch[channel].conf0.mem_pd = pd_en; 147 | return ESP_OK; 148 | } 149 | 150 | esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool* pd_en) 151 | { 152 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 153 | *pd_en = (bool) RMT.conf_ch[channel].conf0.mem_pd; 154 | return ESP_OK; 155 | } 156 | 157 | esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst) 158 | { 159 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 160 | portENTER_CRITICAL(&rmt_spinlock); 161 | if(tx_idx_rst) { 162 | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; 163 | } 164 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX; 165 | RMT.conf_ch[channel].conf1.tx_start = 1; 166 | portEXIT_CRITICAL(&rmt_spinlock); 167 | return ESP_OK; 168 | } 169 | 170 | esp_err_t rmt_tx_stop(rmt_channel_t channel) 171 | { 172 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 173 | portENTER_CRITICAL(&rmt_spinlock); 174 | RMT.conf_ch[channel].conf1.tx_start = 0; 175 | portEXIT_CRITICAL(&rmt_spinlock); 176 | return ESP_OK; 177 | } 178 | 179 | esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst) 180 | { 181 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 182 | portENTER_CRITICAL(&rmt_spinlock); 183 | if(rx_idx_rst) { 184 | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; 185 | } 186 | RMT.conf_ch[channel].conf1.rx_en = 0; 187 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX; 188 | RMT.conf_ch[channel].conf1.rx_en = 1; 189 | portEXIT_CRITICAL(&rmt_spinlock); 190 | return ESP_OK; 191 | } 192 | 193 | esp_err_t rmt_rx_stop(rmt_channel_t channel) 194 | { 195 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 196 | portENTER_CRITICAL(&rmt_spinlock); 197 | RMT.conf_ch[channel].conf1.rx_en = 0; 198 | portEXIT_CRITICAL(&rmt_spinlock); 199 | return ESP_OK; 200 | } 201 | 202 | esp_err_t rmt_memory_rw_rst(rmt_channel_t channel) 203 | { 204 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 205 | portENTER_CRITICAL(&rmt_spinlock); 206 | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; 207 | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; 208 | portEXIT_CRITICAL(&rmt_spinlock); 209 | return ESP_OK; 210 | } 211 | 212 | esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner) 213 | { 214 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 215 | RMT_CHECK(owner < RMT_MEM_OWNER_MAX, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG); 216 | portENTER_CRITICAL(&rmt_spinlock); 217 | RMT.conf_ch[channel].conf1.mem_owner = owner; 218 | portEXIT_CRITICAL(&rmt_spinlock); 219 | return ESP_OK; 220 | } 221 | 222 | esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner) 223 | { 224 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 225 | RMT_CHECK(owner != NULL, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG); 226 | *owner = (rmt_mem_owner_t) RMT.conf_ch[channel].conf1.mem_owner; 227 | return ESP_OK; 228 | } 229 | 230 | esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en) 231 | { 232 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 233 | portENTER_CRITICAL(&rmt_spinlock); 234 | RMT.conf_ch[channel].conf1.tx_conti_mode = loop_en; 235 | portEXIT_CRITICAL(&rmt_spinlock); 236 | return ESP_OK; 237 | } 238 | 239 | esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool* loop_en) 240 | { 241 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 242 | *loop_en = (bool) RMT.conf_ch[channel].conf1.tx_conti_mode; 243 | return ESP_OK; 244 | } 245 | 246 | esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh) 247 | { 248 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 249 | portENTER_CRITICAL(&rmt_spinlock); 250 | RMT.conf_ch[channel].conf1.rx_filter_en = rx_filter_en; 251 | RMT.conf_ch[channel].conf1.rx_filter_thres = thresh; 252 | portEXIT_CRITICAL(&rmt_spinlock); 253 | return ESP_OK; 254 | } 255 | 256 | esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk) 257 | { 258 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 259 | RMT_CHECK(base_clk < RMT_BASECLK_MAX, RMT_BASECLK_ERROR_STR, ESP_ERR_INVALID_ARG); 260 | portENTER_CRITICAL(&rmt_spinlock); 261 | RMT.conf_ch[channel].conf1.ref_always_on = base_clk; 262 | portEXIT_CRITICAL(&rmt_spinlock); 263 | return ESP_OK; 264 | } 265 | 266 | esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t* src_clk) 267 | { 268 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 269 | *src_clk = (rmt_source_clk_t) (RMT.conf_ch[channel].conf1.ref_always_on); 270 | return ESP_OK; 271 | } 272 | 273 | esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level) 274 | { 275 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 276 | RMT_CHECK(level < RMT_IDLE_LEVEL_MAX, "RMT IDLE LEVEL ERR", ESP_ERR_INVALID_ARG); 277 | portENTER_CRITICAL(&rmt_spinlock); 278 | RMT.conf_ch[channel].conf1.idle_out_en = idle_out_en; 279 | RMT.conf_ch[channel].conf1.idle_out_lv = level; 280 | portEXIT_CRITICAL(&rmt_spinlock); 281 | return ESP_OK; 282 | } 283 | 284 | esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t* status) 285 | { 286 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 287 | *status = RMT.status_ch[channel]; 288 | return ESP_OK; 289 | } 290 | 291 | rmt_data_mode_t rmt_get_data_mode() 292 | { 293 | return (rmt_data_mode_t) (RMT.apb_conf.fifo_mask); 294 | } 295 | 296 | void rmt_set_intr_enable_mask(uint32_t mask) 297 | { 298 | portENTER_CRITICAL(&rmt_spinlock); 299 | RMT.int_ena.val |= mask; 300 | portEXIT_CRITICAL(&rmt_spinlock); 301 | } 302 | 303 | void rmt_clr_intr_enable_mask(uint32_t mask) 304 | { 305 | portENTER_CRITICAL(&rmt_spinlock); 306 | RMT.int_ena.val &= (~mask); 307 | portEXIT_CRITICAL(&rmt_spinlock); 308 | } 309 | 310 | esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en) 311 | { 312 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 313 | if(en) { 314 | rmt_set_intr_enable_mask(BIT(channel * 3 + 1)); 315 | } else { 316 | rmt_clr_intr_enable_mask(BIT(channel * 3 + 1)); 317 | } 318 | return ESP_OK; 319 | } 320 | 321 | esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en) 322 | { 323 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 324 | if(en) { 325 | rmt_set_intr_enable_mask(BIT(channel * 3 + 2)); 326 | } else { 327 | rmt_clr_intr_enable_mask(BIT(channel * 3 + 2)); 328 | } 329 | return ESP_OK; 330 | } 331 | 332 | esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en) 333 | { 334 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 335 | if(en) { 336 | rmt_set_intr_enable_mask(BIT(channel * 3)); 337 | } else { 338 | rmt_clr_intr_enable_mask(BIT(channel * 3)); 339 | } 340 | return ESP_OK; 341 | } 342 | 343 | esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh) 344 | { 345 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 346 | RMT_CHECK(evt_thresh < 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG); 347 | if(en) { 348 | RMT.tx_lim_ch[channel].limit = evt_thresh; 349 | rmt_set_tx_wrap_en(channel, true); 350 | rmt_set_intr_enable_mask(BIT(channel + 24)); 351 | } else { 352 | rmt_clr_intr_enable_mask(BIT(channel + 24)); 353 | } 354 | return ESP_OK; 355 | } 356 | 357 | esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num) 358 | { 359 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 360 | RMT_CHECK(mode < RMT_MODE_MAX, RMT_MODE_ERROR_STR, ESP_ERR_INVALID_ARG); 361 | RMT_CHECK(((GPIO_IS_VALID_GPIO(gpio_num) && (mode == RMT_MODE_RX)) || (GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) && (mode == RMT_MODE_TX))), 362 | RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG); 363 | 364 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], 2); 365 | if(mode == RMT_MODE_TX) { 366 | gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT); 367 | gpio_matrix_out(gpio_num, RMT_SIG_OUT0_IDX + channel, 0, 0); 368 | } else { 369 | gpio_set_direction(gpio_num, GPIO_MODE_INPUT); 370 | gpio_matrix_in(gpio_num, RMT_SIG_IN0_IDX + channel, 0); 371 | } 372 | return ESP_OK; 373 | } 374 | 375 | esp_err_t rmt_config(rmt_config_t* rmt_param) 376 | { 377 | uint8_t mode = rmt_param->rmt_mode; 378 | uint8_t channel = rmt_param->channel; 379 | uint8_t gpio_num = rmt_param->gpio_num; 380 | uint8_t mem_cnt = rmt_param->mem_block_num; 381 | int clk_div = rmt_param->clk_div; 382 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 383 | RMT_CHECK(GPIO_IS_VALID_GPIO(gpio_num), RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG); 384 | RMT_CHECK((mem_cnt + channel <= 8 && mem_cnt > 0), RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG); 385 | RMT_CHECK((clk_div > 0), RMT_CLK_DIV_ERROR_STR, ESP_ERR_INVALID_ARG); 386 | periph_module_enable(PERIPH_RMT_MODULE); 387 | 388 | RMT.conf_ch[channel].conf0.div_cnt = clk_div; 389 | /*Visit data use memory not FIFO*/ 390 | rmt_set_data_mode(RMT_DATA_MODE_MEM); 391 | /*Reset tx/rx memory index */ 392 | portENTER_CRITICAL(&rmt_spinlock); 393 | RMT.conf_ch[channel].conf1.mem_rd_rst = 1; 394 | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; 395 | portEXIT_CRITICAL(&rmt_spinlock); 396 | 397 | if(mode == RMT_MODE_TX) { 398 | uint32_t rmt_source_clk_hz = 0; 399 | uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz; 400 | uint16_t carrier_duty_percent = rmt_param->tx_config.carrier_duty_percent; 401 | uint8_t carrier_level = rmt_param->tx_config.carrier_level; 402 | uint8_t idle_level = rmt_param->tx_config.idle_level; 403 | 404 | portENTER_CRITICAL(&rmt_spinlock); 405 | RMT.conf_ch[channel].conf1.tx_conti_mode = rmt_param->tx_config.loop_en; 406 | /*Memory set block number*/ 407 | RMT.conf_ch[channel].conf0.mem_size = mem_cnt; 408 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX; 409 | /*We use APB clock in this version, which is 80Mhz, later we will release system reference clock*/ 410 | RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB; 411 | rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB); 412 | /*Set idle level */ 413 | RMT.conf_ch[channel].conf1.idle_out_en = rmt_param->tx_config.idle_output_en; 414 | RMT.conf_ch[channel].conf1.idle_out_lv = idle_level; 415 | portEXIT_CRITICAL(&rmt_spinlock); 416 | 417 | /*Set carrier*/ 418 | uint32_t duty_div, duty_h, duty_l; 419 | duty_div = rmt_source_clk_hz / carrier_freq_hz; 420 | duty_h = duty_div * carrier_duty_percent / 100; 421 | duty_l = duty_div - duty_h; 422 | RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level; 423 | RMT.carrier_duty_ch[channel].high = duty_h; 424 | RMT.carrier_duty_ch[channel].low = duty_l; 425 | RMT.conf_ch[channel].conf0.carrier_en = rmt_param->tx_config.carrier_en; 426 | ESP_LOGD(RMT_TAG, "Rmt Tx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Carrier_Hz %u|Duty %u", 427 | channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent); 428 | } 429 | else if(RMT_MODE_RX == mode) { 430 | uint8_t filter_cnt = rmt_param->rx_config.filter_ticks_thresh; 431 | uint16_t threshold = rmt_param->rx_config.idle_threshold; 432 | 433 | portENTER_CRITICAL(&rmt_spinlock); 434 | /*clock init*/ 435 | RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB; 436 | uint32_t rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB); 437 | /*memory set block number and owner*/ 438 | RMT.conf_ch[channel].conf0.mem_size = mem_cnt; 439 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX; 440 | /*Set idle threshold*/ 441 | RMT.conf_ch[channel].conf0.idle_thres = threshold; 442 | /* Set RX filter */ 443 | RMT.conf_ch[channel].conf1.rx_filter_thres = filter_cnt; 444 | RMT.conf_ch[channel].conf1.rx_filter_en = rmt_param->rx_config.filter_en; 445 | portEXIT_CRITICAL(&rmt_spinlock); 446 | 447 | ESP_LOGD(RMT_TAG, "Rmt Rx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Thresold %u|Filter %u", 448 | channel, gpio_num, rmt_source_clk_hz, clk_div, threshold, filter_cnt); 449 | } 450 | rmt_set_pin(channel, mode, gpio_num); 451 | return ESP_OK; 452 | } 453 | 454 | static void IRAM_ATTR rmt_fill_memory(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset) 455 | { 456 | portENTER_CRITICAL(&rmt_spinlock); 457 | RMT.apb_conf.fifo_mask = RMT_DATA_MODE_MEM; 458 | portEXIT_CRITICAL(&rmt_spinlock); 459 | int i; 460 | for(i = 0; i < item_num; i++) { 461 | RMTMEM.chan[channel].data32[i + mem_offset].val = item[i].val; 462 | } 463 | } 464 | 465 | esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset) 466 | { 467 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, (0)); 468 | RMT_CHECK((item != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 469 | RMT_CHECK((item_num > 0), RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG); 470 | 471 | /*Each block has 64 x 32 bits of data*/ 472 | uint8_t mem_cnt = RMT.conf_ch[channel].conf0.mem_size; 473 | RMT_CHECK((mem_cnt * RMT_MEM_ITEM_NUM >= item_num), RMT_WR_MEM_OVF_ERROR_STR, ESP_ERR_INVALID_ARG); 474 | rmt_fill_memory(channel, item, item_num, mem_offset); 475 | return ESP_OK; 476 | } 477 | 478 | esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (*fn)(void*), void * arg) 479 | { 480 | RMT_CHECK((fn != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 481 | RMT_CHECK(s_rmt_driver_installed == false, "RMT DRIVER INSTALLED, CAN NOT REG ISR HANDLER", ESP_FAIL); 482 | portENTER_CRITICAL(&rmt_spinlock); 483 | ESP_INTR_DISABLE(rmt_intr_num); 484 | intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, rmt_intr_num); 485 | xt_set_interrupt_handler(rmt_intr_num, fn, arg); 486 | ESP_INTR_ENABLE(rmt_intr_num); 487 | portEXIT_CRITICAL(&rmt_spinlock); 488 | return ESP_OK; 489 | } 490 | 491 | static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel) 492 | { 493 | int block_num = RMT.conf_ch[channel].conf0.mem_size; 494 | int item_block_len = block_num * RMT_MEM_ITEM_NUM; 495 | volatile rmt_item32_t* data = RMTMEM.chan[channel].data32; 496 | int idx; 497 | int cnt; 498 | 499 | ////printf("block num: %d item_block_len: %d\n\r",block_num, item_block_len ); 500 | for(idx = 0; idx < item_block_len; idx++) { 501 | if(data[idx].duration0 == 0) { 502 | ////printf("duration 0:%x\n\r", data[idx].duration0); 503 | return idx; 504 | } else if(data[idx].duration1 == 0) { 505 | //////printf("duration 1:%d, idx:%d \n\r", data[idx].duration0,idx); 506 | 507 | for(cnt=0; cnt < idx+1; cnt++) 508 | { 509 | ////printf("level,%d,period:%d,level:%d,period:%d \n\r", tNEC_ITEM_DURATION(data[cnt].level1), tNEC_ITEM_DURATION(data[cnt].duration1), tNEC_ITEM_DURATION(data[cnt].level0), tNEC_ITEM_DURATION(data[cnt].duration0) ); 510 | } 511 | 512 | 513 | return idx + 1; 514 | } 515 | } 516 | 517 | 518 | return idx; 519 | } 520 | 521 | static void IRAM_ATTR rmt_driver_isr_default(void* arg) 522 | { 523 | ////printf("in the ISR\n"); 524 | uint32_t intr_st = RMT.int_st.val; 525 | ////printf("Interrupt value triggered:%d\n\r", intr_st); 526 | uint32_t i = 0; 527 | uint8_t channel; 528 | portBASE_TYPE HPTaskAwoken = 0; 529 | for(i = 0; i < 32; i++) { 530 | if(i < 24) { 531 | //////printf("first 24 bits \n"); 532 | if(intr_st & (BIT(i))) { 533 | channel = i / 3; 534 | rmt_obj_t* p_rmt = p_rmt_obj[channel]; 535 | switch(i % 3) { 536 | //TX END 537 | case 0: 538 | ////printf("ISR:case 0:\n\r"); 539 | ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : TX END\n"); 540 | xSemaphoreGiveFromISR(p_rmt->tx_sem, &HPTaskAwoken); 541 | if(HPTaskAwoken == pdTRUE) { 542 | portYIELD_FROM_ISR(); 543 | } 544 | p_rmt->tx_data = NULL; 545 | p_rmt->tx_len_rem = 0; 546 | p_rmt->tx_offset = 0; 547 | p_rmt->tx_sub_len = 0; 548 | break; 549 | //RX_END 550 | case 1: 551 | ////printf("ISR:case 1:\n\r"); 552 | ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : RX END"); 553 | ////printf("channel %d receive end\n\r", channel); 554 | RMT.conf_ch[channel].conf1.rx_en = 0; 555 | int item_len = rmt_get_mem_len(channel); 556 | ////printf("data received length %d\n\r", item_len); 557 | //change memory owner to protect data. 558 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;//changed from tx to RX 559 | if(p_rmt->rx_buf) { 560 | BaseType_t res = xRingbufferSendFromISR(p_rmt->rx_buf, (void*) RMTMEM.chan[channel].data32, item_len * 4, &HPTaskAwoken); 561 | ////printf("data sent to ring buffer with res %d\n\r", res); 562 | 563 | if(res == pdFALSE) { 564 | ESP_LOGE(RMT_TAG, "RMT RX BUFFER FULL"); 565 | } else { 566 | 567 | } 568 | if(HPTaskAwoken == pdTRUE) { 569 | portYIELD_FROM_ISR(); 570 | } 571 | } else { 572 | ESP_EARLY_LOGE(RMT_TAG, "RMT RX BUFFER ERROR\n"); 573 | } 574 | RMT.conf_ch[channel].conf1.mem_wr_rst = 1; 575 | RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX; 576 | RMT.conf_ch[channel].conf1.rx_en = 1; 577 | break; 578 | //ERR 579 | case 2: 580 | ////printf("ISR:case 2:\n\r"); 581 | ESP_EARLY_LOGE(RMT_TAG, "RMT[%d] ERR", channel); 582 | ESP_EARLY_LOGE(RMT_TAG, "status: 0x%08x", RMT.status_ch[channel]); 583 | RMT.int_ena.val &= (~(BIT(i))); 584 | break; 585 | default: 586 | ////printf("in default case"); 587 | break; 588 | } 589 | RMT.int_clr.val = BIT(i); 590 | } 591 | } else { 592 | if(intr_st & (BIT(i))) { 593 | channel = i - 24; 594 | rmt_obj_t* p_rmt = p_rmt_obj[channel]; 595 | RMT.int_clr.val = BIT(i); 596 | ESP_EARLY_LOGD(RMT_TAG, "RMT CH[%d]: EVT INTR", channel); 597 | if(p_rmt->tx_data == NULL) { 598 | //skip 599 | } else { 600 | 601 | rmt_item32_t* pdata = p_rmt->tx_data; 602 | int len_rem = p_rmt->tx_len_rem; 603 | if(len_rem >= p_rmt->tx_sub_len) { 604 | rmt_fill_memory(channel, pdata, p_rmt->tx_sub_len, p_rmt->tx_offset); 605 | p_rmt->tx_data += p_rmt->tx_sub_len; 606 | p_rmt->tx_len_rem -= p_rmt->tx_sub_len; 607 | } else if(len_rem == 0) { 608 | RMTMEM.chan[channel].data32[p_rmt->tx_offset].val = 0; 609 | } else { 610 | rmt_fill_memory(channel, pdata, len_rem, p_rmt->tx_offset); 611 | RMTMEM.chan[channel].data32[p_rmt->tx_offset + len_rem].val = 0; 612 | p_rmt->tx_data += len_rem; 613 | p_rmt->tx_len_rem -= len_rem; 614 | } 615 | if(p_rmt->tx_offset == 0) { 616 | p_rmt->tx_offset = p_rmt->tx_sub_len; 617 | } else { 618 | p_rmt->tx_offset = 0; 619 | } 620 | } 621 | } 622 | } 623 | } 624 | } 625 | 626 | esp_err_t rmt_driver_uninstall(rmt_channel_t channel) 627 | { 628 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 629 | if(p_rmt_obj[channel] == NULL) { 630 | return ESP_OK; 631 | } 632 | xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY); 633 | rmt_set_rx_intr_en(channel, 0); 634 | rmt_set_err_intr_en(channel, 0); 635 | rmt_set_tx_intr_en(channel, 0); 636 | rmt_set_evt_intr_en(channel, 0, 0xffff); 637 | if(p_rmt_obj[channel]->tx_sem) { 638 | vSemaphoreDelete(p_rmt_obj[channel]->tx_sem); 639 | p_rmt_obj[channel]->tx_sem = NULL; 640 | } 641 | if(p_rmt_obj[channel]->rx_buf) { 642 | vRingbufferDelete(p_rmt_obj[channel]->rx_buf); 643 | p_rmt_obj[channel]->rx_buf = NULL; 644 | } 645 | free(p_rmt_obj[channel]); 646 | p_rmt_obj[channel] = NULL; 647 | s_rmt_driver_installed = false; 648 | return ESP_OK; 649 | } 650 | 651 | esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num) 652 | { 653 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 654 | if(p_rmt_obj[channel] != NULL) { 655 | ESP_LOGD(RMT_TAG, "RMT DRIVER ALREADY INSTALLED"); 656 | return ESP_FAIL; 657 | } 658 | 659 | ESP_INTR_DISABLE(rmt_intr_num); 660 | p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t)); 661 | 662 | if(p_rmt_obj[channel] == NULL) { 663 | ESP_LOGE(RMT_TAG, "RMT driver malloc error"); 664 | return ESP_FAIL; 665 | } 666 | memset(p_rmt_obj[channel], 0, sizeof(rmt_obj_t)); 667 | 668 | p_rmt_obj[channel]->tx_len_rem = 0; 669 | p_rmt_obj[channel]->tx_data = NULL; 670 | p_rmt_obj[channel]->channel = channel; 671 | p_rmt_obj[channel]->tx_offset = 0; 672 | p_rmt_obj[channel]->tx_sub_len = 0; 673 | 674 | if(p_rmt_obj[channel]->tx_sem == NULL) { 675 | p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinary(); 676 | xSemaphoreGive(p_rmt_obj[channel]->tx_sem); 677 | } 678 | if(p_rmt_obj[channel]->rx_buf == NULL && rx_buf_size > 0) { 679 | p_rmt_obj[channel]->rx_buf = xRingbufferCreate(rx_buf_size, RINGBUF_TYPE_NOSPLIT); 680 | rmt_set_rx_intr_en(channel, 1); 681 | rmt_set_err_intr_en(channel, 1); 682 | } 683 | if(s_rmt_driver_installed == false) { 684 | rmt_isr_register(rmt_intr_num, rmt_driver_isr_default, NULL); 685 | s_rmt_driver_installed = true; 686 | } 687 | rmt_set_tx_intr_en(channel, 1); 688 | ESP_INTR_ENABLE(rmt_intr_num); 689 | return ESP_OK; 690 | } 691 | 692 | esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t* rmt_item, int item_num, bool wait_tx_done) 693 | { 694 | //printf("inside rmt_write_items\n\r"); 695 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 696 | RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL); 697 | RMT_CHECK(rmt_item != NULL, RMT_ADDR_ERROR_STR, ESP_FAIL); 698 | RMT_CHECK(item_num > 0, RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG); 699 | rmt_obj_t* p_rmt = p_rmt_obj[channel]; 700 | int block_num = RMT.conf_ch[channel].conf0.mem_size; 701 | int item_block_len = block_num * RMT_MEM_ITEM_NUM; 702 | int item_sub_len = block_num * RMT_MEM_ITEM_NUM / 2; 703 | int len_rem = item_num; 704 | xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY); 705 | // fill the memory block first 706 | if(item_num >= item_block_len) { 707 | rmt_fill_memory(channel, rmt_item, item_block_len, 0); 708 | RMT.tx_lim_ch[channel].limit = item_sub_len; 709 | RMT.apb_conf.mem_tx_wrap_en = 1; 710 | len_rem -= item_block_len; 711 | RMT.conf_ch[channel].conf1.tx_conti_mode = 0; 712 | rmt_set_evt_intr_en(channel, 1, item_sub_len); 713 | p_rmt->tx_data = rmt_item + item_block_len; 714 | p_rmt->tx_len_rem = len_rem; 715 | p_rmt->tx_offset = 0; 716 | p_rmt->tx_sub_len = item_sub_len; 717 | } else { 718 | rmt_fill_memory(channel, rmt_item, len_rem, 0); 719 | RMTMEM.chan[channel].data32[len_rem].val = 0; 720 | len_rem = 0; 721 | } 722 | //printf("starting data transfer...\n\r"); 723 | rmt_tx_start(channel, true); 724 | if(wait_tx_done) { 725 | xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY); 726 | xSemaphoreGive(p_rmt->tx_sem); 727 | } 728 | //printf("starting data transfer complete..\n\r"); 729 | 730 | return ESP_OK; 731 | } 732 | 733 | esp_err_t rmt_wait_tx_done(rmt_channel_t channel) 734 | { 735 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 736 | RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL); 737 | xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY); 738 | xSemaphoreGive(p_rmt_obj[channel]->tx_sem); 739 | return ESP_OK; 740 | } 741 | 742 | esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_handler) 743 | { 744 | RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); 745 | RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL); 746 | RMT_CHECK(buf_handler != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG); 747 | *buf_handler = p_rmt_obj[channel]->rx_buf; 748 | return ESP_OK; 749 | } 750 | 751 | -------------------------------------------------------------------------------- /rmt.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef _DRIVER_RMT_CTRL_H_ 16 | #define _DRIVER_RMT_CTRL_H_ 17 | #include "esp_err.h" 18 | #include "soc/rmt_reg.h" 19 | #include "soc/dport_reg.h" 20 | #include "soc/rmt_struct.h" 21 | #include "freertos/FreeRTOS.h" 22 | #include "freertos/semphr.h" 23 | #include "freertos/xtensa_api.h" 24 | #include "freertos/ringbuf.h" 25 | #include "driver/gpio.h" 26 | #include "driver/periph_ctrl.h" 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #define RMT_MEM_BLOCK_BYTE_NUM (256) 33 | #define RMT_MEM_ITEM_NUM (RMT_MEM_BLOCK_BYTE_NUM/4) 34 | 35 | typedef enum { 36 | RMT_CHANNEL_0=0, /*!< RMT Channel0 */ 37 | RMT_CHANNEL_1, /*!< RMT Channel1 */ 38 | RMT_CHANNEL_2, /*!< RMT Channel2 */ 39 | RMT_CHANNEL_3, /*!< RMT Channel3 */ 40 | RMT_CHANNEL_4, /*!< RMT Channel4 */ 41 | RMT_CHANNEL_5, /*!< RMT Channel5 */ 42 | RMT_CHANNEL_6, /*!< RMT Channel6 */ 43 | RMT_CHANNEL_7, /*!< RMT Channel7 */ 44 | RMT_CHANNEL_MAX 45 | } rmt_channel_t; 46 | 47 | typedef enum { 48 | RMT_MEM_OWNER_TX = 0, /*!< RMT RX mode, RMT transmitter owns the memory block*/ 49 | RMT_MEM_OWNER_RX = 1, /*!< RMT RX mode, RMT receiver owns the memory block*/ 50 | RMT_MEM_OWNER_MAX, 51 | }rmt_mem_owner_t; 52 | 53 | typedef enum { 54 | RMT_BASECLK_REF = 0, /*!< RMT source clock system reference tick, 1MHz by default(Not supported in this version) */ 55 | RMT_BASECLK_APB, /*!< RMT source clock is APB CLK, 80Mhz by default */ 56 | RMT_BASECLK_MAX, 57 | } rmt_source_clk_t; 58 | 59 | typedef enum { 60 | RMT_DATA_MODE_FIFO = 0, /*