ソースを参照

rmt: support tx in a group

morris 5 年 前
コミット
dc91aa9786

+ 24 - 0
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

+ 24 - 0
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

+ 112 - 0
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

+ 1 - 1
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
 }