diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index c62858611e..d9ff2b1aa1 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -806,6 +806,30 @@ rmt_tx_end_callback_t rmt_register_tx_end_callback(rmt_tx_end_fn_t function, voi esp_err_t rmt_set_rx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh); #endif +#if RMT_SUPPORT_TX_GROUP +/** +* @brief Add channel into a group (channels in the same group will transmit simultaneously) +* +* @param channel RMT channel +* +* @return +* - ESP_ERR_INVALID_ARG Parameter error +* - ESP_OK Success +*/ +esp_err_t rmt_add_channel_to_group(rmt_channel_t channel); + +/** +* @brief Remove channel out of a group +* +* @param channel RMT channel +* +* @return +* - ESP_ERR_INVALID_ARG Parameter error +* - ESP_OK Success +*/ +esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel); +#endif + #ifdef __cplusplus } #endif diff --git a/components/driver/rmt.c b/components/driver/rmt.c index 2cf4aded85..da52d66633 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -1125,3 +1125,27 @@ esp_err_t rmt_get_counter_clock(rmt_channel_t channel, uint32_t *clock_hz) RMT_EXIT_CRITICAL(); return ESP_OK; } + +#if RMT_SUPPORT_TX_GROUP +esp_err_t rmt_add_channel_to_group(rmt_channel_t channel) +{ + RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); + RMT_ENTER_CRITICAL(); + rmt_ll_enable_tx_sync(p_rmt_obj[channel]->hal.regs, true); + rmt_ll_add_channel_to_group(p_rmt_obj[channel]->hal.regs, channel); + rmt_ll_reset_counter_clock_div(p_rmt_obj[channel]->hal.regs, channel); + RMT_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel) +{ + RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); + RMT_ENTER_CRITICAL(); + if (rmt_ll_remove_channel_from_group(p_rmt_obj[channel]->hal.regs, channel) == 0) { + rmt_ll_enable_tx_sync(p_rmt_obj[channel]->hal.regs, false); + } + RMT_EXIT_CRITICAL(); + return ESP_OK; +} +#endif \ No newline at end of file diff --git a/components/driver/test/test_rmt.c b/components/driver/test/test_rmt.c index 9f425def8a..e306f4e20c 100644 --- a/components/driver/test/test_rmt.c +++ b/components/driver/test/test_rmt.c @@ -393,3 +393,115 @@ TEST_CASE("RMT Ping-Pong operation", "[rmt]") rmt_clean_testbench(tx_channel, rx_channel); } #endif +#if RMT_SUPPORT_TX_GROUP +static uint32_t tx_end_time0, tx_end_time1; +static void rmt_tx_end_cb(rmt_channel_t channel, void *arg) +{ + if (channel == 0) { + tx_end_time0 = esp_cpu_get_ccount(); + } else { + tx_end_time1 = esp_cpu_get_ccount(); + } +} +TEST_CASE("RMT TX simultaneously", "[rmt]") +{ + rmt_item32_t frames[RMT_CHANNEL_MEM_WORDS]; + uint32_t size = sizeof(frames) / sizeof(frames[0]); + int channel0 = 0; + int channel1 = 1; + + int i = 0; + for (i = 0; i < size - 1; i++) { + frames[i].level0 = 1; + frames[i].duration0 = 1000; + frames[i].level1 = 0; + frames[i].duration1 = 1000; + } + frames[i].level0 = 0; + frames[i].duration0 = 0; + frames[i].level1 = 0; + frames[i].duration1 = 0; + + rmt_config_t tx_config0 = RMT_DEFAULT_CONFIG_TX(12, channel0); + rmt_config_t tx_config1 = RMT_DEFAULT_CONFIG_TX(13, channel1); + TEST_ESP_OK(rmt_config(&tx_config0)); + TEST_ESP_OK(rmt_config(&tx_config1)); + + TEST_ESP_OK(rmt_driver_install(channel0, 0, 0)); + TEST_ESP_OK(rmt_driver_install(channel1, 0, 0)); + + rmt_register_tx_end_callback(rmt_tx_end_cb, NULL); + + TEST_ESP_OK(rmt_add_channel_to_group(channel0)); + TEST_ESP_OK(rmt_add_channel_to_group(channel1)); + + TEST_ESP_OK(rmt_write_items(channel0, frames, size, false)); + vTaskDelay(pdMS_TO_TICKS(1000)); + TEST_ESP_OK(rmt_write_items(channel1, frames, size, false)); + + TEST_ESP_OK(rmt_wait_tx_done(channel0, portMAX_DELAY)); + TEST_ESP_OK(rmt_wait_tx_done(channel1, portMAX_DELAY)); + + ESP_LOGI(TAG, "tx_end_time0=%u, tx_end_time1=%u", tx_end_time0, tx_end_time1); + TEST_ASSERT_LESS_OR_EQUAL_UINT32(2000, tx_end_time1 - tx_end_time0); + + TEST_ESP_OK(rmt_remove_channel_from_group(channel0)); + TEST_ESP_OK(rmt_remove_channel_from_group(channel1)); + + TEST_ESP_OK(rmt_driver_uninstall(channel0)); + TEST_ESP_OK(rmt_driver_uninstall(channel1)); + +} +#endif + +#if RMT_SUPPORT_TX_LOOP_COUNT +TEST_CASE("RMT TX loop", "[rmt]") +{ + RingbufHandle_t rb = NULL; + rmt_item32_t *items = NULL; + uint32_t length = 0; + uint32_t addr = 0x10; + uint32_t cmd = 0x20; + bool repeat = false; + int tx_channel = 0; + int rx_channel = 1; + uint32_t count = 0; + + rmt_setup_testbench(tx_channel, rx_channel, RMT_TESTBENCH_FLAGS_LOOP_ON); + + // get ready to receive + TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb)); + TEST_ASSERT_NOT_NULL(rb); + TEST_ESP_OK(rmt_rx_start(rx_channel, true)); + + vTaskDelay(pdMS_TO_TICKS(1000)); + + // build NEC codes + ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr); + // Send new key code + TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd)); + TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length)); + TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done + + // parse NEC codes + while (rb) { + items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000); + if (items) { + length /= 4; // one RMT = 4 Bytes + if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) { + if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) { + count++; + ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd); + } + } + vRingbufferReturnItem(rb, (void *) items); + } else { + ESP_LOGI(TAG, "done"); + break; + } + } + + TEST_ASSERT_EQUAL(10, count); + rmt_clean_testbench(tx_channel, rx_channel); +} +#endif diff --git a/components/soc/soc/esp32s2/include/soc/rmt_caps.h b/components/soc/soc/esp32s2/include/soc/rmt_caps.h index 10ea3bcffb..048d0ab95a 100644 --- a/components/soc/soc/esp32s2/include/soc/rmt_caps.h +++ b/components/soc/soc/esp32s2/include/soc/rmt_caps.h @@ -23,7 +23,7 @@ extern "C" { #define RMT_SUPPORT_RX_PINGPONG (1) /*!< Support Ping-Pong mode on RX path */ #define RMT_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ #define RMT_SUPPORT_TX_LOOP_COUNT (1) /*!< Support transmit specified number of cycles in loop mode */ -#define RMT_SUPPORT_TX_SIMULTANEOUS (1) /*!< Support multiple channel transmit simultaneously */ +#define RMT_SUPPORT_TX_GROUP (1) /*!< Support a group of TX channels to transmit simultaneously */ #ifdef __cplusplus }