rmt: support tx in a group

This commit is contained in:
morris 2020-03-19 15:26:49 +08:00
parent fa167eb0c5
commit dc91aa9786
4 changed files with 161 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}