rmt_rx.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/cdefs.h>
  9. #include <sys/param.h>
  10. #include "sdkconfig.h"
  11. #if CONFIG_RMT_ENABLE_DEBUG_LOG
  12. // The local log level must be defined before including esp_log.h
  13. // Set the maximum log level for this source file
  14. #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
  15. #endif
  16. #include "esp_log.h"
  17. #include "esp_check.h"
  18. #include "esp_memory_utils.h"
  19. #include "esp_rom_gpio.h"
  20. #include "soc/rmt_periph.h"
  21. #include "soc/rtc.h"
  22. #include "hal/rmt_ll.h"
  23. #include "hal/gpio_hal.h"
  24. #include "driver/gpio.h"
  25. #include "driver/rmt_rx.h"
  26. #include "rmt_private.h"
  27. #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
  28. static const char *TAG = "rmt";
  29. static esp_err_t rmt_del_rx_channel(rmt_channel_handle_t channel);
  30. static esp_err_t rmt_rx_demodulate_carrier(rmt_channel_handle_t channel, const rmt_carrier_config_t *config);
  31. static esp_err_t rmt_rx_enable(rmt_channel_handle_t channel);
  32. static esp_err_t rmt_rx_disable(rmt_channel_handle_t channel);
  33. static void rmt_rx_default_isr(void *args);
  34. #if SOC_RMT_SUPPORT_DMA
  35. static bool rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
  36. static void rmt_rx_mount_dma_buffer(dma_descriptor_t *desc_array, size_t array_size, const void *buffer, size_t buffer_size)
  37. {
  38. size_t prepared_length = 0;
  39. uint8_t *data = (uint8_t *)buffer;
  40. int dma_node_i = 0;
  41. dma_descriptor_t *desc = NULL;
  42. while (buffer_size > RMT_DMA_DESC_BUF_MAX_SIZE) {
  43. desc = &desc_array[dma_node_i];
  44. desc->dw0.suc_eof = 0;
  45. desc->dw0.size = RMT_DMA_DESC_BUF_MAX_SIZE;
  46. desc->dw0.length = 0;
  47. desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
  48. desc->buffer = &data[prepared_length];
  49. desc->next = &desc_array[dma_node_i + 1];
  50. prepared_length += RMT_DMA_DESC_BUF_MAX_SIZE;
  51. buffer_size -= RMT_DMA_DESC_BUF_MAX_SIZE;
  52. dma_node_i++;
  53. }
  54. if (buffer_size) {
  55. desc = &desc_array[dma_node_i];
  56. desc->dw0.suc_eof = 0;
  57. desc->dw0.size = buffer_size;
  58. desc->dw0.length = 0;
  59. desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
  60. desc->buffer = &data[prepared_length];
  61. prepared_length += buffer_size;
  62. }
  63. desc->next = NULL; // one-off DMA chain
  64. }
  65. static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx_channel_config_t *config)
  66. {
  67. gdma_channel_alloc_config_t dma_chan_config = {
  68. .direction = GDMA_CHANNEL_DIRECTION_RX,
  69. };
  70. ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed");
  71. gdma_strategy_config_t gdma_strategy_conf = {
  72. .auto_update_desc = true,
  73. .owner_check = true,
  74. };
  75. gdma_apply_strategy(rx_channel->base.dma_chan, &gdma_strategy_conf);
  76. gdma_rx_event_callbacks_t cbs = {
  77. .on_recv_eof = rmt_dma_rx_eof_cb,
  78. };
  79. gdma_register_rx_event_callbacks(rx_channel->base.dma_chan, &cbs, rx_channel);
  80. return ESP_OK;
  81. }
  82. #endif // SOC_RMT_SUPPORT_DMA
  83. static esp_err_t rmt_rx_register_to_group(rmt_rx_channel_t *rx_channel, const rmt_rx_channel_config_t *config)
  84. {
  85. size_t mem_block_num = 0;
  86. // start to search for a free channel
  87. // a channel can take up its neighbour's memory block, so the neighbour channel won't work, we should skip these "invaded" ones
  88. int channel_scan_start = RMT_RX_CHANNEL_OFFSET_IN_GROUP;
  89. int channel_scan_end = RMT_RX_CHANNEL_OFFSET_IN_GROUP + SOC_RMT_RX_CANDIDATES_PER_GROUP;
  90. if (config->flags.with_dma) {
  91. // for DMA mode, the memory block number is always 1; for non-DMA mode, memory block number is configured by user
  92. mem_block_num = 1;
  93. // Only the last channel has the DMA capability
  94. channel_scan_start = RMT_RX_CHANNEL_OFFSET_IN_GROUP + SOC_RMT_RX_CANDIDATES_PER_GROUP - 1;
  95. rx_channel->ping_pong_symbols = 0; // with DMA, we don't need to do ping-pong
  96. } else {
  97. // one channel can occupy multiple memory blocks
  98. mem_block_num = config->mem_block_symbols / SOC_RMT_MEM_WORDS_PER_CHANNEL;
  99. if (mem_block_num * SOC_RMT_MEM_WORDS_PER_CHANNEL < config->mem_block_symbols) {
  100. mem_block_num++;
  101. }
  102. rx_channel->ping_pong_symbols = mem_block_num * SOC_RMT_MEM_WORDS_PER_CHANNEL / 2;
  103. }
  104. rx_channel->base.mem_block_num = mem_block_num;
  105. // search free channel and then register to the group
  106. // memory blocks used by one channel must be continuous
  107. uint32_t channel_mask = (1 << mem_block_num) - 1;
  108. rmt_group_t *group = NULL;
  109. int channel_id = -1;
  110. for (int i = 0; i < SOC_RMT_GROUPS; i++) {
  111. group = rmt_acquire_group_handle(i);
  112. ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i);
  113. portENTER_CRITICAL(&group->spinlock);
  114. for (int j = channel_scan_start; j < channel_scan_end; j++) {
  115. if (!(group->occupy_mask & (channel_mask << j))) {
  116. group->occupy_mask |= (channel_mask << j);
  117. // the channel ID should index from 0
  118. channel_id = j - RMT_RX_CHANNEL_OFFSET_IN_GROUP;
  119. group->rx_channels[channel_id] = rx_channel;
  120. break;
  121. }
  122. }
  123. portEXIT_CRITICAL(&group->spinlock);
  124. if (channel_id < 0) {
  125. // didn't find a capable channel in the group, don't forget to release the group handle
  126. rmt_release_group_handle(group);
  127. group = NULL;
  128. } else {
  129. rx_channel->base.channel_id = channel_id;
  130. rx_channel->base.channel_mask = channel_mask;
  131. rx_channel->base.group = group;
  132. break;
  133. }
  134. }
  135. ESP_RETURN_ON_FALSE(channel_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free rx channels");
  136. return ESP_OK;
  137. }
  138. static void rmt_rx_unregister_from_group(rmt_channel_t *channel, rmt_group_t *group)
  139. {
  140. portENTER_CRITICAL(&group->spinlock);
  141. group->rx_channels[channel->channel_id] = NULL;
  142. group->occupy_mask &= ~(channel->channel_mask << (channel->channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP));
  143. portEXIT_CRITICAL(&group->spinlock);
  144. // channel has a reference on group, release it now
  145. rmt_release_group_handle(group);
  146. }
  147. static esp_err_t rmt_rx_destory(rmt_rx_channel_t *rx_channel)
  148. {
  149. if (rx_channel->base.intr) {
  150. ESP_RETURN_ON_ERROR(esp_intr_free(rx_channel->base.intr), TAG, "delete interrupt service failed");
  151. }
  152. if (rx_channel->base.pm_lock) {
  153. ESP_RETURN_ON_ERROR(esp_pm_lock_delete(rx_channel->base.pm_lock), TAG, "delete pm_lock failed");
  154. }
  155. #if SOC_RMT_SUPPORT_DMA
  156. if (rx_channel->base.dma_chan) {
  157. ESP_RETURN_ON_ERROR(gdma_del_channel(rx_channel->base.dma_chan), TAG, "delete dma channel failed");
  158. }
  159. #endif // SOC_RMT_SUPPORT_DMA
  160. if (rx_channel->base.group) {
  161. // de-register channel from RMT group
  162. rmt_rx_unregister_from_group(&rx_channel->base, rx_channel->base.group);
  163. }
  164. free(rx_channel);
  165. return ESP_OK;
  166. }
  167. esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_handle_t *ret_chan)
  168. {
  169. #if CONFIG_RMT_ENABLE_DEBUG_LOG
  170. esp_log_level_set(TAG, ESP_LOG_DEBUG);
  171. #endif
  172. esp_err_t ret = ESP_OK;
  173. rmt_rx_channel_t *rx_channel = NULL;
  174. ESP_GOTO_ON_FALSE(config && ret_chan && config->resolution_hz, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
  175. ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid GPIO number");
  176. ESP_GOTO_ON_FALSE((config->mem_block_symbols & 0x01) == 0 && config->mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL,
  177. ESP_ERR_INVALID_ARG, err, TAG, "mem_block_symbols must be even and at least %d", SOC_RMT_MEM_WORDS_PER_CHANNEL);
  178. #if !SOC_RMT_SUPPORT_DMA
  179. ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported");
  180. #endif // SOC_RMT_SUPPORT_DMA
  181. size_t num_dma_nodes = 0;
  182. if (config->flags.with_dma) {
  183. num_dma_nodes = config->mem_block_symbols * sizeof(rmt_symbol_word_t) / RMT_DMA_DESC_BUF_MAX_SIZE + 1;
  184. }
  185. // malloc channel memory
  186. uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
  187. if (config->flags.with_dma) {
  188. // DMA descriptors must be placed in internal SRAM
  189. mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
  190. }
  191. rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t) + num_dma_nodes * sizeof(dma_descriptor_t), mem_caps);
  192. ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel");
  193. rx_channel->num_dma_nodes = num_dma_nodes;
  194. // register the channel to group
  195. ESP_GOTO_ON_ERROR(rmt_rx_register_to_group(rx_channel, config), err, TAG, "register channel failed");
  196. rmt_group_t *group = rx_channel->base.group;
  197. rmt_hal_context_t *hal = &group->hal;
  198. int channel_id = rx_channel->base.channel_id;
  199. int group_id = group->group_id;
  200. // select the clock source
  201. ESP_GOTO_ON_ERROR(rmt_select_periph_clock(&rx_channel->base, config->clk_src), err, TAG, "set group clock failed");
  202. // reset channel, make sure the RX engine is not working, and events are cleared
  203. portENTER_CRITICAL(&group->spinlock);
  204. rmt_hal_rx_channel_reset(&group->hal, channel_id);
  205. portEXIT_CRITICAL(&group->spinlock);
  206. // When channel receives an end-maker, a DMA in_suc_eof interrupt will be generated
  207. // So we don't rely on RMT interrupt any more, GDMA event callback is sufficient
  208. if (config->flags.with_dma) {
  209. #if SOC_RMT_SUPPORT_DMA
  210. ESP_GOTO_ON_ERROR(rmt_rx_init_dma_link(rx_channel, config), err, TAG, "install rx DMA failed");
  211. #endif // SOC_RMT_SUPPORT_DMA
  212. } else {
  213. // RMT interrupt is mandatory if the channel doesn't use DMA
  214. int isr_flags = RMT_INTR_ALLOC_FLAG;
  215. ret = esp_intr_alloc_intrstatus(rmt_periph_signals.groups[group_id].irq, isr_flags,
  216. (uint32_t)rmt_ll_get_interrupt_status_reg(hal->regs),
  217. RMT_LL_EVENT_RX_MASK(channel_id), rmt_rx_default_isr, rx_channel, &rx_channel->base.intr);
  218. ESP_GOTO_ON_ERROR(ret, err, TAG, "install rx interrupt failed");
  219. }
  220. // set channel clock resolution
  221. uint32_t real_div = group->resolution_hz / config->resolution_hz;
  222. rmt_ll_rx_set_channel_clock_div(hal->regs, channel_id, real_div);
  223. // resolution loss due to division, calculate the real resolution
  224. rx_channel->base.resolution_hz = group->resolution_hz / real_div;
  225. if (rx_channel->base.resolution_hz != config->resolution_hz) {
  226. ESP_LOGW(TAG, "channel resolution loss, real=%"PRIu32, rx_channel->base.resolution_hz);
  227. }
  228. rmt_ll_rx_set_mem_blocks(hal->regs, channel_id, rx_channel->base.mem_block_num);
  229. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_HW);
  230. #if SOC_RMT_SUPPORT_RX_PINGPONG
  231. rmt_ll_rx_set_limit(hal->regs, channel_id, rx_channel->ping_pong_symbols);
  232. // always enable rx wrap, both DMA mode and ping-pong mode rely this feature
  233. rmt_ll_rx_enable_wrap(hal->regs, channel_id, true);
  234. #endif
  235. #if SOC_RMT_SUPPORT_RX_DEMODULATION
  236. // disable carrier demodulation by default, can reenable by `rmt_apply_carrier()`
  237. rmt_ll_rx_enable_carrier_demodulation(hal->regs, channel_id, false);
  238. #endif
  239. // GPIO Matrix/MUX configuration
  240. rx_channel->base.gpio_num = config->gpio_num;
  241. gpio_config_t gpio_conf = {
  242. .intr_type = GPIO_INTR_DISABLE,
  243. // also enable the input path is `io_loop_back` is on, this is useful for debug
  244. .mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0),
  245. .pull_down_en = false,
  246. .pull_up_en = true,
  247. .pin_bit_mask = 1ULL << config->gpio_num,
  248. };
  249. ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config GPIO failed");
  250. esp_rom_gpio_connect_in_signal(config->gpio_num,
  251. rmt_periph_signals.groups[group_id].channels[channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP].rx_sig,
  252. config->flags.invert_in);
  253. gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_num], PIN_FUNC_GPIO);
  254. // initialize other members of rx channel
  255. rx_channel->base.direction = RMT_CHANNEL_DIRECTION_RX;
  256. rx_channel->base.fsm = RMT_FSM_INIT;
  257. rx_channel->base.hw_mem_base = &RMTMEM.channels[channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP].symbols[0];
  258. rx_channel->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
  259. // polymorphic methods
  260. rx_channel->base.del = rmt_del_rx_channel;
  261. rx_channel->base.set_carrier_action = rmt_rx_demodulate_carrier;
  262. rx_channel->base.enable = rmt_rx_enable;
  263. rx_channel->base.disable = rmt_rx_disable;
  264. // return general channel handle
  265. *ret_chan = &rx_channel->base;
  266. ESP_LOGD(TAG, "new rx channel(%d,%d) at %p, gpio=%d, res=%"PRIu32"Hz, hw_mem_base=%p, ping_pong_size=%d",
  267. group_id, channel_id, rx_channel, config->gpio_num, rx_channel->base.resolution_hz,
  268. rx_channel->base.hw_mem_base, rx_channel->ping_pong_symbols);
  269. return ESP_OK;
  270. err:
  271. if (rx_channel) {
  272. rmt_rx_destory(rx_channel);
  273. }
  274. return ret;
  275. }
  276. static esp_err_t rmt_del_rx_channel(rmt_channel_handle_t channel)
  277. {
  278. rmt_rx_channel_t *rx_chan = __containerof(channel, rmt_rx_channel_t, base);
  279. rmt_group_t *group = channel->group;
  280. int group_id = group->group_id;
  281. int channel_id = channel->channel_id;
  282. ESP_LOGD(TAG, "del rx channel(%d,%d)", group_id, channel_id);
  283. // recycle memory resource
  284. ESP_RETURN_ON_ERROR(rmt_rx_destory(rx_chan), TAG, "destory rx channel failed");
  285. return ESP_OK;
  286. }
  287. esp_err_t rmt_rx_register_event_callbacks(rmt_channel_handle_t channel, const rmt_rx_event_callbacks_t *cbs, void *user_data)
  288. {
  289. ESP_RETURN_ON_FALSE(channel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  290. ESP_RETURN_ON_FALSE(channel->direction == RMT_CHANNEL_DIRECTION_RX, ESP_ERR_INVALID_ARG, TAG, "invalid channel direction");
  291. rmt_rx_channel_t *rx_chan = __containerof(channel, rmt_rx_channel_t, base);
  292. #if CONFIG_RMT_ISR_IRAM_SAFE
  293. if (cbs->on_recv_done) {
  294. ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_done), ESP_ERR_INVALID_ARG, TAG, "on_recv_done callback not in IRAM");
  295. }
  296. if (user_data) {
  297. ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM");
  298. }
  299. #endif
  300. rx_chan->on_recv_done = cbs->on_recv_done;
  301. rx_chan->user_data = user_data;
  302. return ESP_OK;
  303. }
  304. esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_size, const rmt_receive_config_t *config)
  305. {
  306. ESP_RETURN_ON_FALSE(channel && buffer && buffer_size && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
  307. ESP_RETURN_ON_FALSE(channel->direction == RMT_CHANNEL_DIRECTION_RX, ESP_ERR_INVALID_ARG, TAG, "invalid channel direction");
  308. ESP_RETURN_ON_FALSE(channel->fsm == RMT_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "channel not in enable state");
  309. rmt_rx_channel_t *rx_chan = __containerof(channel, rmt_rx_channel_t, base);
  310. if (channel->dma_chan) {
  311. ESP_RETURN_ON_FALSE(esp_ptr_internal(buffer), ESP_ERR_INVALID_ARG, TAG, "buffer must locate in internal RAM for DMA use");
  312. }
  313. if (channel->dma_chan) {
  314. ESP_RETURN_ON_FALSE(buffer_size <= rx_chan->num_dma_nodes * RMT_DMA_DESC_BUF_MAX_SIZE,
  315. ESP_ERR_INVALID_ARG, TAG, "buffer size exceeds DMA capacity");
  316. }
  317. rmt_group_t *group = channel->group;
  318. rmt_hal_context_t *hal = &group->hal;
  319. int channel_id = channel->channel_id;
  320. // fill in the transaction descriptor
  321. rmt_rx_trans_desc_t *t = &rx_chan->trans_desc;
  322. t->buffer = buffer;
  323. t->buffer_size = buffer_size;
  324. t->received_symbol_num = 0;
  325. t->copy_dest_off = 0;
  326. if (channel->dma_chan) {
  327. #if SOC_RMT_SUPPORT_DMA
  328. rmt_rx_mount_dma_buffer(rx_chan->dma_nodes, rx_chan->num_dma_nodes, buffer, buffer_size);
  329. gdma_reset(channel->dma_chan);
  330. gdma_start(channel->dma_chan, (intptr_t)rx_chan->dma_nodes);
  331. #endif
  332. }
  333. rx_chan->mem_off = 0;
  334. portENTER_CRITICAL(&channel->spinlock);
  335. // reset memory writer offset
  336. rmt_ll_rx_reset_pointer(hal->regs, channel_id);
  337. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_HW);
  338. // set sampling parameters of incoming signals
  339. rmt_ll_rx_set_filter_thres(hal->regs, channel_id, ((uint64_t)group->resolution_hz * config->signal_range_min_ns) / 1000000000UL);
  340. rmt_ll_rx_enable_filter(hal->regs, channel_id, config->signal_range_min_ns != 0);
  341. rmt_ll_rx_set_idle_thres(hal->regs, channel_id, ((uint64_t)channel->resolution_hz * config->signal_range_max_ns) / 1000000000UL);
  342. // turn on RMT RX machine
  343. rmt_ll_rx_enable(hal->regs, channel_id, true);
  344. portEXIT_CRITICAL(&channel->spinlock);
  345. return ESP_OK;
  346. }
  347. static esp_err_t rmt_rx_demodulate_carrier(rmt_channel_handle_t channel, const rmt_carrier_config_t *config)
  348. {
  349. #if !SOC_RMT_SUPPORT_RX_DEMODULATION
  350. ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "rx demodulation not supported");
  351. #else
  352. rmt_group_t *group = channel->group;
  353. rmt_hal_context_t *hal = &group->hal;
  354. int group_id = group->group_id;
  355. int channel_id = channel->channel_id;
  356. uint32_t real_frequency = 0;
  357. if (config && config->frequency_hz) {
  358. // carrier demodulation module works base on channel clock (this is different from TX carrier modulation mode)
  359. uint32_t total_ticks = channel->resolution_hz / config->frequency_hz; // Note this division operation will lose precision
  360. uint32_t high_ticks = total_ticks * config->duty_cycle;
  361. uint32_t low_ticks = total_ticks - high_ticks;
  362. portENTER_CRITICAL(&channel->spinlock);
  363. rmt_ll_rx_set_carrier_level(hal->regs, channel_id, !config->flags.polarity_active_low);
  364. rmt_ll_rx_set_carrier_high_low_ticks(hal->regs, channel_id, high_ticks, low_ticks);
  365. portEXIT_CRITICAL(&channel->spinlock);
  366. // save real carrier frequency
  367. real_frequency = channel->resolution_hz / (high_ticks + low_ticks);
  368. }
  369. // enable/disable carrier demodulation
  370. portENTER_CRITICAL(&channel->spinlock);
  371. rmt_ll_rx_enable_carrier_demodulation(hal->regs, channel_id, real_frequency > 0);
  372. portEXIT_CRITICAL(&channel->spinlock);
  373. if (real_frequency > 0) {
  374. ESP_LOGD(TAG, "enable carrier demodulation for channel(%d,%d), freq=%"PRIu32"Hz", group_id, channel_id, real_frequency);
  375. } else {
  376. ESP_LOGD(TAG, "disable carrier demodulation for channel(%d, %d)", group_id, channel_id);
  377. }
  378. return ESP_OK;
  379. #endif
  380. }
  381. static esp_err_t rmt_rx_enable(rmt_channel_handle_t channel)
  382. {
  383. rmt_group_t *group = channel->group;
  384. rmt_hal_context_t *hal = &group->hal;
  385. int channel_id = channel->channel_id;
  386. // acquire power manager lock
  387. if (channel->pm_lock) {
  388. ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(channel->pm_lock), TAG, "acquire pm_lock failed");
  389. }
  390. if (channel->dma_chan) {
  391. #if SOC_RMT_SUPPORT_DMA
  392. // enable the DMA access mode
  393. portENTER_CRITICAL(&channel->spinlock);
  394. rmt_ll_rx_enable_dma(hal->regs, channel_id, true);
  395. portEXIT_CRITICAL(&channel->spinlock);
  396. gdma_connect(channel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_RMT, 0));
  397. #endif // SOC_RMT_SUPPORT_DMA
  398. } else {
  399. portENTER_CRITICAL(&group->spinlock);
  400. rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_RX_MASK(channel_id), true);
  401. portEXIT_CRITICAL(&group->spinlock);
  402. }
  403. channel->fsm = RMT_FSM_ENABLE;
  404. return ESP_OK;
  405. }
  406. static esp_err_t rmt_rx_disable(rmt_channel_handle_t channel)
  407. {
  408. rmt_group_t *group = channel->group;
  409. rmt_hal_context_t *hal = &group->hal;
  410. int channel_id = channel->channel_id;
  411. portENTER_CRITICAL(&channel->spinlock);
  412. rmt_ll_rx_enable(hal->regs, channel_id, false);
  413. portEXIT_CRITICAL(&channel->spinlock);
  414. if (channel->dma_chan) {
  415. #if SOC_RMT_SUPPORT_DMA
  416. gdma_stop(channel->dma_chan);
  417. gdma_disconnect(channel->dma_chan);
  418. portENTER_CRITICAL(&channel->spinlock);
  419. rmt_ll_rx_enable_dma(hal->regs, channel_id, false);
  420. portEXIT_CRITICAL(&channel->spinlock);
  421. #endif
  422. } else {
  423. portENTER_CRITICAL(&group->spinlock);
  424. rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_RX_MASK(channel_id), false);
  425. rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_MASK(channel_id));
  426. portEXIT_CRITICAL(&group->spinlock);
  427. }
  428. // release power manager lock
  429. if (channel->pm_lock) {
  430. ESP_RETURN_ON_ERROR(esp_pm_lock_release(channel->pm_lock), TAG, "release pm_lock failed");
  431. }
  432. channel->fsm = RMT_FSM_INIT;
  433. return ESP_OK;
  434. }
  435. static size_t IRAM_ATTR rmt_copy_symbols(rmt_symbol_word_t *symbol_stream, size_t symbol_num, void *buffer, size_t offset, size_t buffer_size)
  436. {
  437. size_t mem_want = symbol_num * sizeof(rmt_symbol_word_t);
  438. size_t mem_have = buffer_size - offset;
  439. size_t copy_size = MIN(mem_want, mem_have);
  440. // do memory copy
  441. memcpy(buffer + offset, symbol_stream, copy_size);
  442. return copy_size;
  443. }
  444. static bool IRAM_ATTR rmt_isr_handle_rx_done(rmt_rx_channel_t *rx_chan)
  445. {
  446. rmt_channel_t *channel = &rx_chan->base;
  447. rmt_group_t *group = channel->group;
  448. rmt_hal_context_t *hal = &group->hal;
  449. uint32_t channel_id = channel->channel_id;
  450. rmt_rx_trans_desc_t *trans_desc = &rx_chan->trans_desc;
  451. bool need_yield = false;
  452. rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_DONE(channel_id));
  453. portENTER_CRITICAL_ISR(&channel->spinlock);
  454. // disable the RX engine, it will be enabled again when next time user calls `rmt_receive()`
  455. rmt_ll_rx_enable(hal->regs, channel_id, false);
  456. uint32_t offset = rmt_ll_rx_get_memory_writer_offset(hal->regs, channel_id);
  457. // sanity check
  458. assert(offset > rx_chan->mem_off);
  459. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_SW);
  460. // copy the symbols to user space
  461. size_t stream_symbols = offset - rx_chan->mem_off;
  462. size_t copy_size = rmt_copy_symbols(channel->hw_mem_base + rx_chan->mem_off, stream_symbols,
  463. trans_desc->buffer, trans_desc->copy_dest_off, trans_desc->buffer_size);
  464. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_HW);
  465. portEXIT_CRITICAL_ISR(&channel->spinlock);
  466. #if !SOC_RMT_SUPPORT_RX_PINGPONG
  467. // for chips doesn't support ping-pong RX, we should check whether the receiver has encountered with a long frame,
  468. // whose length is longer than the channel capacity
  469. if (rmt_ll_rx_get_interrupt_status_raw(hal->regs, channel_id) & RMT_LL_EVENT_RX_ERROR(channel_id)) {
  470. portENTER_CRITICAL_ISR(&channel->spinlock);
  471. rmt_ll_rx_reset_pointer(hal->regs, channel_id);
  472. portEXIT_CRITICAL_ISR(&channel->spinlock);
  473. // this clear operation can only take effect after we copy out the received data and reset the pointer
  474. rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_ERROR(channel_id));
  475. ESP_DRAM_LOGE(TAG, "hw buffer too small, received symbols truncated");
  476. }
  477. #endif // !SOC_RMT_SUPPORT_RX_PINGPONG
  478. // check whether all symbols are copied
  479. if (copy_size != stream_symbols * sizeof(rmt_symbol_word_t)) {
  480. ESP_DRAM_LOGE(TAG, "user buffer too small, received symbols truncated");
  481. }
  482. trans_desc->copy_dest_off += copy_size;
  483. trans_desc->received_symbol_num += copy_size / sizeof(rmt_symbol_word_t);
  484. // notify the user with receive RMT symbols
  485. if (rx_chan->on_recv_done) {
  486. rmt_rx_done_event_data_t edata = {
  487. .received_symbols = trans_desc->buffer,
  488. .num_symbols = trans_desc->received_symbol_num,
  489. };
  490. if (rx_chan->on_recv_done(channel, &edata, rx_chan->user_data)) {
  491. need_yield = true;
  492. }
  493. }
  494. return need_yield;
  495. }
  496. #if SOC_RMT_SUPPORT_RX_PINGPONG
  497. static bool IRAM_ATTR rmt_isr_handle_rx_threshold(rmt_rx_channel_t *rx_chan)
  498. {
  499. rmt_channel_t *channel = &rx_chan->base;
  500. rmt_group_t *group = channel->group;
  501. rmt_hal_context_t *hal = &group->hal;
  502. uint32_t channel_id = channel->channel_id;
  503. rmt_rx_trans_desc_t *trans_desc = &rx_chan->trans_desc;
  504. rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_THRES(channel_id));
  505. portENTER_CRITICAL_ISR(&channel->spinlock);
  506. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_SW);
  507. // copy the symbols to user space
  508. size_t copy_size = rmt_copy_symbols(channel->hw_mem_base + rx_chan->mem_off, rx_chan->ping_pong_symbols,
  509. trans_desc->buffer, trans_desc->copy_dest_off, trans_desc->buffer_size);
  510. rmt_ll_rx_set_mem_owner(hal->regs, channel_id, RMT_LL_MEM_OWNER_HW);
  511. portEXIT_CRITICAL_ISR(&channel->spinlock);
  512. // check whether all symbols are copied
  513. if (copy_size != rx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t)) {
  514. ESP_DRAM_LOGE(TAG, "received symbols truncated");
  515. }
  516. trans_desc->copy_dest_off += copy_size;
  517. trans_desc->received_symbol_num += copy_size / sizeof(rmt_symbol_word_t);
  518. // update the hw memory offset, where stores the next RMT symbols to copy
  519. rx_chan->mem_off = rx_chan->ping_pong_symbols - rx_chan->mem_off;
  520. return false;
  521. }
  522. #endif // SOC_RMT_SUPPORT_RX_PINGPONG
  523. static void IRAM_ATTR rmt_rx_default_isr(void *args)
  524. {
  525. rmt_rx_channel_t *rx_chan = (rmt_rx_channel_t *)args;
  526. rmt_channel_t *channel = &rx_chan->base;
  527. rmt_group_t *group = channel->group;
  528. rmt_hal_context_t *hal = &group->hal;
  529. uint32_t channel_id = channel->channel_id;
  530. bool need_yield = false;
  531. uint32_t status = rmt_ll_rx_get_interrupt_status(hal->regs, channel_id);
  532. #if SOC_RMT_SUPPORT_RX_PINGPONG
  533. // RX threshold interrupt
  534. if (status & RMT_LL_EVENT_RX_THRES(channel_id)) {
  535. if (rmt_isr_handle_rx_threshold(rx_chan)) {
  536. need_yield = true;
  537. }
  538. }
  539. #endif // SOC_RMT_SUPPORT_RX_PINGPONG
  540. // RX end interrupt
  541. if (status & RMT_LL_EVENT_RX_DONE(channel_id)) {
  542. if (rmt_isr_handle_rx_done(rx_chan)) {
  543. need_yield = true;
  544. }
  545. }
  546. if (need_yield) {
  547. portYIELD_FROM_ISR();
  548. }
  549. }
  550. #if SOC_RMT_SUPPORT_DMA
  551. static size_t IRAM_ATTR rmt_rx_get_received_symbol_num_from_dma(dma_descriptor_t *desc)
  552. {
  553. size_t received_bytes = 0;
  554. while (desc) {
  555. received_bytes += desc->dw0.length;
  556. desc = desc->next;
  557. }
  558. received_bytes = ALIGN_UP(received_bytes, sizeof(rmt_symbol_word_t));
  559. return received_bytes / sizeof(rmt_symbol_word_t);
  560. }
  561. static bool IRAM_ATTR rmt_dma_rx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
  562. {
  563. bool need_yield = false;
  564. rmt_rx_channel_t *rx_chan = (rmt_rx_channel_t *)user_data;
  565. rmt_channel_t *channel = &rx_chan->base;
  566. rmt_group_t *group = channel->group;
  567. rmt_hal_context_t *hal = &group->hal;
  568. rmt_rx_trans_desc_t *trans_desc = &rx_chan->trans_desc;
  569. uint32_t channel_id = channel->channel_id;
  570. portENTER_CRITICAL_ISR(&channel->spinlock);
  571. // disable the RX engine, it will be enabled again in the next `rmt_receive()`
  572. rmt_ll_rx_enable(hal->regs, channel_id, false);
  573. portEXIT_CRITICAL_ISR(&channel->spinlock);
  574. if (rx_chan->on_recv_done) {
  575. rmt_rx_done_event_data_t edata = {
  576. .received_symbols = trans_desc->buffer,
  577. .num_symbols = rmt_rx_get_received_symbol_num_from_dma(rx_chan->dma_nodes),
  578. };
  579. if (rx_chan->on_recv_done(channel, &edata, rx_chan->user_data)) {
  580. need_yield = true;
  581. }
  582. }
  583. return need_yield;
  584. }
  585. #endif // SOC_RMT_SUPPORT_DMA