Prechádzať zdrojové kódy

rmt: better support rx demodulation

morris 6 rokov pred
rodič
commit
855b316045

+ 5 - 6
components/driver/include/driver/rmt.h

@@ -56,12 +56,11 @@ typedef struct {
     uint16_t idle_threshold;     /*!< RMT RX idle threshold */
     uint8_t filter_ticks_thresh; /*!< RMT filter tick number */
     bool filter_en;              /*!< RMT receiver filter enable */
-
-#ifdef RMT_SUPPORT_RX_DEMODULATION
-    bool rm_carrier;             /*!< RMT receiver remove carrier enable */
-    uint16_t high_thres;         /*!< The threshold of carrier high level tick number */
-    uint16_t low_thres;          /*!< The threshold of carrier low level tick number */
-    rmt_carrier_level_t carrier_level;  /*!< The level need to remove carrier */
+#if RMT_SUPPORT_RX_DEMODULATION
+    bool rm_carrier;                   /*!< RMT receiver remove carrier enable */
+    uint32_t carrier_freq_hz;          /*!< RMT carrier frequency */
+    uint8_t carrier_duty_percent;      /*!< RMT carrier duty (%) */
+    rmt_carrier_level_t carrier_level; /*!< The level to remove the carrier */
 #endif
 } rmt_rx_config_t;
 

+ 9 - 5
components/driver/rmt.c

@@ -486,7 +486,6 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
     }
     rmt_ll_set_mem_blocks(dev, channel, mem_cnt);
     rmt_ll_set_mem_owner(dev, channel, RMT_MEM_OWNER_HW);
-    rmt_ll_enable_carrier(dev, channel, false); // disable carrier feature by default
     RMT_EXIT_CRITICAL();
 
     s_rmt_src_clock_hz[channel] = rmt_source_clk_hz;
@@ -534,10 +533,15 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
         rmt_ll_enable_rx_pingpong(dev, channel, true);
 #endif
 
-#ifdef RMT_SUPPORT_RX_DEMODULATION
-        rmt_ll_enable_rx_carrier_rm(dev, channel, rmt_param->rx_config.rm_carrier);
-        rmt_ll_set_rx_carrier_high_low_ticks(dev, channel, rmt_param->rx_config.high_thres, rmt_param->rx_config.low_thres );
-        rmt_ll_set_carrier_on_level(dev, channel, rmt_param->rx_config.carrier_level);
+#if RMT_SUPPORT_RX_DEMODULATION
+        rmt_ll_enable_carrier(dev, channel, rmt_param->rx_config.rm_carrier);
+        if (rmt_param->rx_config.rm_carrier) {
+            uint32_t duty_total = rmt_source_clk_hz / rmt_ll_get_counter_clock_div(dev, channel) / rmt_param->rx_config.carrier_freq_hz;
+            uint32_t duty_high = duty_total * rmt_param->rx_config.carrier_duty_percent / 100;
+            // there could be residual in timing the carrier pulse, so double enlarge the theoretical value
+            rmt_ll_set_rx_carrier_high_low_ticks(dev, channel, duty_high * 2, (duty_total - duty_high) * 2);
+            rmt_ll_set_carrier_on_level(dev, channel, rmt_param->rx_config.carrier_level);
+        }
 #endif
         RMT_EXIT_CRITICAL();
 

+ 79 - 103
components/driver/test/test_rmt.c

@@ -14,6 +14,9 @@
 // CI ONLY: Don't connect any other signals to this GPIO
 #define RMT_DATA_IO (12) // bind signal RMT_SIG_OUT0_IDX and RMT_SIG_IN0_IDX on the same GPIO
 
+#define RMT_TESTBENCH_FLAGS_ALWAYS_ON (1<<0)
+#define RMT_TESTBENCH_FLAGS_CARRIER_ON (1<<1)
+
 static const char *TAG = "RMT.test";
 static ir_builder_t *s_ir_builder = NULL;
 static ir_parser_t *s_ir_parser = NULL;
@@ -23,13 +26,28 @@ static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
     // RMT channel configuration
     if (tx_channel >= 0) {
         rmt_config_t tx_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, tx_channel);
-        tx_config.flags = flags;
+        if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
+            tx_config.flags |= RMT_CHANNEL_FLAGS_ALWAYS_ON;
+        }
+        if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
+            tx_config.tx_config.carrier_en = true;
+        }
         TEST_ESP_OK(rmt_config(&tx_config));
     }
 
     if (rx_channel >= 0) {
         rmt_config_t rx_config = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, rx_channel);
-        rx_config.flags = flags;
+        if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
+            rx_config.flags |= RMT_CHANNEL_FLAGS_ALWAYS_ON;
+        }
+#if RMT_SUPPORT_RX_DEMODULATION
+        if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
+            rx_config.rx_config.rm_carrier = true;
+            rx_config.rx_config.carrier_freq_hz = 38000;
+            rx_config.rx_config.carrier_duty_percent = 33;
+            rx_config.rx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
+        }
+#endif
         TEST_ESP_OK(rmt_config(&rx_config));
     }
 
@@ -168,7 +186,7 @@ TEST_CASE("RMT install/uninstall test", "[rmt][pressure]")
     }
 }
 
-TEST_CASE("RMT NEC TX and RX", "[rmt][timeout=240]")
+static void do_nec_tx_rx(uint32_t flags)
 {
     RingbufHandle_t rb = NULL;
     rmt_item32_t *items = NULL;
@@ -179,56 +197,72 @@ TEST_CASE("RMT NEC TX and RX", "[rmt][timeout=240]")
     int tx_channel = 0;
     int rx_channel = 1;
 
-    uint32_t test_flags[] = {0, RMT_CHANNEL_FLAGS_ALWAYS_ON}; // test REF_TICK clock source
-
     // test on different flags combinations
-    for (int run = 0; run < sizeof(test_flags) / sizeof(test_flags[0]); run++) {
-        rmt_setup_testbench(tx_channel, rx_channel, test_flags[run]);
-
-        // 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
-        cmd = 0x20;
-        while (cmd <= 0x30) {
-            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));
-            if (cmd & 0x01) {
-                TEST_ESP_OK(rmt_write_items(tx_channel, items, length, false)); // no wait
-                TEST_ESP_OK(rmt_wait_tx_done(tx_channel, portMAX_DELAY));
-            } else {
-                TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
-            }
-            cmd++;
+    rmt_setup_testbench(tx_channel, rx_channel, flags);
+
+    // 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
+    cmd = 0x20;
+    while (cmd <= 0x30) {
+        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));
+        if (cmd & 0x01) {
+            TEST_ESP_OK(rmt_write_items(tx_channel, items, length, false)); // no wait
+            TEST_ESP_OK(rmt_wait_tx_done(tx_channel, portMAX_DELAY));
+        } else {
+            TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
         }
+        cmd++;
+    }
 
-        // 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) {
-                        ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
-                    }
+    // 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) {
+                    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;
             }
+            vRingbufferReturnItem(rb, (void *) items);
+        } else {
+            ESP_LOGI(TAG, "done");
+            break;
         }
-
-        TEST_ASSERT_EQUAL(0x30, cmd);
-        rmt_clean_testbench(tx_channel, rx_channel);
     }
+
+    TEST_ASSERT_EQUAL(0x30, cmd);
+    rmt_clean_testbench(tx_channel, rx_channel);
+}
+
+// basic nec tx and rx test, using APB source clock, no modulation
+TEST_CASE("RMT NEC TX and RX (APB)", "[rmt]")
+{
+    do_nec_tx_rx(0);
+}
+
+// test with RMT_TESTBENCH_FLAGS_ALWAYS_ON will take a long time (REF_TICK is much slower than APB CLOCK)
+TEST_CASE("RMT NEC TX and RX (REF_TICK)", "[rmt][timeout=240]")
+{
+    do_nec_tx_rx(RMT_TESTBENCH_FLAGS_ALWAYS_ON);
+}
+
+#if RMT_SUPPORT_RX_DEMODULATION
+// basic nec tx and rx test, using APB source clock, with modulation and demodulation on
+TEST_CASE("RMT NEC TX and RX (Modulation/Demodulation)", "[rmt]")
+{
+    do_nec_tx_rx(RMT_TESTBENCH_FLAGS_CARRIER_ON);
 }
+#endif
 
 TEST_CASE("RMT TX (RMT_CHANNEL_MEM_WORDS-1) symbols", "[rmt][boundary]")
 {
@@ -312,61 +346,3 @@ TEST_CASE("RMT TX stop", "[rmt]")
     TEST_ASSERT(num < count);
     rmt_clean_testbench(tx_channel, rx_channel);
 }
-
-#ifdef RMT_SUPPORT_RX_DEMODULATION
-/**
- * @brief RMT demoudulation receiver initialization
- */
-static void rx_demoudulation_init(void)
-{
-    rmt_rx_config_t rx_cfg = {
-        .filter_en = true,
-        .filter_ticks_thresh = 100,
-        .idle_threshold = RMT_ITEM32_TIMEOUT_US / 10 * (RMT_TICK_10_US),
-        .rm_carrier = true,
-        .high_thres = 20,
-        .low_thres = 20,
-        .carrier_level = RMT_CARRIER_LEVEL_HIGH,
-    };
-    rmt_config_t rmt_rx = {
-        .channel = RMT_RX_CHANNEL,
-        .gpio_num = RMT_RX_GPIO_NUM,
-        .clk_div = RMT_CLK_DIV,
-        .mem_block_num = 1,
-        .rmt_mode = RMT_MODE_RX,
-        .rx_config = rx_cfg,
-    };
-    rmt_config(&rmt_rx);
-    rmt_driver_install(rmt_rx.channel, (sizeof(rmt_item32_t) * DATA_ITEM_NUM * (RMT_TX_DATA_NUM + 6)), 0);
-}
-
-TEST_CASE("RMT carrier TX and RX", "[rmt][test_env=UT_T1_RMT]")
-{
-    rx_demoudulation_init();
-    RingbufHandle_t rb = NULL;
-    rmt_get_ringbuf_handle(RMT_RX_CHANNEL, &rb);
-    rmt_rx_start(RMT_RX_CHANNEL, 1);
-    ESP_LOGI(TAG, "Star receiving RMT data...");
-
-    tx_init();
-    rmt_set_tx_carrier(RMT_TX_CHANNEL, true, 1052, 1052, RMT_CARRIER_LEVEL_HIGH);
-    uint16_t cmd = 0x0;
-    uint16_t addr = 0x11;
-    int num_items = DATA_ITEM_NUM * RMT_TX_DATA_NUM;
-    rmt_item32_t *items = calloc(num_items + 1, sizeof(rmt_item32_t));
-
-    vTaskDelay(pdMS_TO_TICKS(2000));
-
-    ESP_LOGI(TAG, "Sending RMT data...");
-    // send data
-    set_tx_data(RMT_TX_CHANNEL, cmd, addr, num_items, items, 0);
-    // wait until tx done
-    rmt_write_items(RMT_TX_CHANNEL, items, num_items, 1);
-    free(items);
-    // receive data
-    uint16_t tmp = get_rx_data(rb);
-    TEST_ASSERT(tmp == RMT_TX_DATA_NUM);
-    TEST_ESP_OK(rmt_driver_uninstall(RMT_TX_CHANNEL));
-    TEST_ESP_OK(rmt_driver_uninstall(RMT_RX_CHANNEL));
-}
-#endif

+ 4 - 1
docs/en/api-reference/peripherals/rmt.rst

@@ -148,7 +148,10 @@ In receive mode, set **rx_config** and the following members of :cpp:type:`rmt_r
 * Enable a filter on the input of the RMT receiver - **filter_en**
 * A threshold of the filter, set in the number of ticks - **filter_ticks_thresh**. Pulses shorter than this setting will be filtered out. Note, that the range of entered tick values is [0..255].
 * A pulse length threshold that will turn the RMT receiver idle, set in number of ticks - **idle_threshold**. The receiver will ignore pulses longer than this setting.
-
+:esp32s2: * Enable the RMT carrier demodulation - **carrier_rm**
+:esp32s2: * Frequency of the carrier in Hz - **carrier_freq_hz**
+:esp32s2: * Duty cycle of the carrier signal in percent (%) - **carrier_duty_percent**
+:esp32s2: * Level of the RMT input, where the carrier is modulated to - **carrier_level**
 
 Finalize Configuration
 ^^^^^^^^^^^^^^^^^^^^^^