Эх сурвалжийг харах

rmt: support tx loop count

morris 5 жил өмнө
parent
commit
0c17af3ea4

+ 3 - 0
components/driver/include/driver/rmt.h

@@ -44,6 +44,9 @@ typedef struct {
     rmt_carrier_level_t carrier_level; /*!< Level of the RMT output, when the carrier is applied */
     rmt_idle_level_t idle_level;       /*!< RMT idle level */
     uint8_t carrier_duty_percent;      /*!< RMT carrier duty (%) */
+#if RMT_SUPPORT_TX_LOOP_COUNT
+    uint32_t loop_count;               /*!< Maximum loop count */
+#endif
     bool carrier_en;                   /*!< RMT carrier enable */
     bool loop_en;                      /*!< Enable sending RMT items in a loop */
     bool idle_output_en;               /*!< RMT idle level output enable */

+ 44 - 3
components/driver/rmt.c

@@ -193,7 +193,17 @@ esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst)
         rmt_ll_reset_tx_pointer(p_rmt_obj[channel]->hal.regs, channel);
     }
     rmt_ll_clear_tx_end_interrupt(p_rmt_obj[channel]->hal.regs, channel);
-    rmt_ll_enable_tx_end_interrupt(p_rmt_obj[channel]->hal.regs, channel, true);
+    // enable tx end interrupt in non-loop mode
+    if (!rmt_ll_is_tx_loop_enabled(p_rmt_obj[channel]->hal.regs, channel)) {
+        rmt_ll_enable_tx_end_interrupt(p_rmt_obj[channel]->hal.regs, channel, true);
+    } else {
+#if RMT_SUPPORT_TX_LOOP_COUNT
+        rmt_ll_reset_tx_loop(p_rmt_obj[channel]->hal.regs, channel);
+        rmt_ll_enable_tx_loop_count(p_rmt_obj[channel]->hal.regs, channel, true);
+        rmt_ll_clear_tx_loop_interrupt(p_rmt_obj[channel]->hal.regs, channel);
+        rmt_ll_enable_tx_loop_interrupt(p_rmt_obj[channel]->hal.regs, channel, true);
+#endif
+    }
     rmt_ll_start_tx(p_rmt_obj[channel]->hal.regs, channel);
     RMT_EXIT_CRITICAL();
     return ESP_OK;
@@ -497,6 +507,11 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par
 
         RMT_ENTER_CRITICAL();
         rmt_ll_enable_tx_loop(dev, channel, rmt_param->tx_config.loop_en);
+#if RMT_SUPPORT_TX_LOOP_COUNT
+        if (rmt_param->tx_config.loop_en) {
+            rmt_ll_set_tx_loop_count(dev, channel, rmt_param->tx_config.loop_count);
+        }
+#endif
         /* always enable tx ping-pong */
         rmt_ll_enable_tx_pingpong(dev, true);
         /*Set idle level */
@@ -770,6 +785,23 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg)
     }
 #endif
 
+#if RMT_SUPPORT_TX_LOOP_COUNT
+    // loop count interrupt
+    status = rmt_ll_get_tx_loop_interrupt_status(hal->regs);
+    while (status) {
+        channel = __builtin_ffs(status) - 1;
+        status &= ~(1 << channel);
+        rmt_obj_t *p_rmt = p_rmt_obj[channel];
+        if (p_rmt) {
+            xSemaphoreGiveFromISR(p_rmt->tx_sem, &HPTaskAwoken);
+            if (rmt_tx_end_callback.function != NULL) {
+                rmt_tx_end_callback.function(channel, rmt_tx_end_callback.arg);
+            }
+        }
+        rmt_ll_clear_tx_loop_interrupt(hal->regs, channel);
+    }
+#endif
+
     // Err interrupt
     status = rmt_ll_get_err_interrupt_status(hal->regs);
     while (status) {
@@ -983,8 +1015,17 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t *rmt_item, i
     rmt_tx_start(channel, true);
     p_rmt->wait_done = wait_tx_done;
     if (wait_tx_done) {
-        xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
-        xSemaphoreGive(p_rmt->tx_sem);
+        // wait loop done
+        if (rmt_ll_is_tx_loop_enabled(p_rmt_obj[channel]->hal.regs, channel)) {
+#if RMT_SUPPORT_TX_LOOP_COUNT
+            xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
+            xSemaphoreGive(p_rmt->tx_sem);
+#endif
+        } else {
+            // wait tx end
+            xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
+            xSemaphoreGive(p_rmt->tx_sem);
+        }
     }
     return ESP_OK;
 }

+ 13 - 0
components/driver/test/test_rmt.c

@@ -16,6 +16,7 @@
 
 #define RMT_TESTBENCH_FLAGS_ALWAYS_ON (1<<0)
 #define RMT_TESTBENCH_FLAGS_CARRIER_ON (1<<1)
+#define RMT_TESTBENCH_FLAGS_LOOP_ON (1<<2)
 
 static const char *TAG = "RMT.test";
 static ir_builder_t *s_ir_builder = NULL;
@@ -32,6 +33,12 @@ static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
         if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
             tx_config.tx_config.carrier_en = true;
         }
+#if RMT_SUPPORT_TX_LOOP_COUNT
+        if (flags & RMT_TESTBENCH_FLAGS_LOOP_ON) {
+            tx_config.tx_config.loop_en = true;
+            tx_config.tx_config.loop_count = 10;
+        }
+#endif
         TEST_ESP_OK(rmt_config(&tx_config));
     }
 
@@ -455,6 +462,10 @@ TEST_CASE("RMT TX simultaneously", "[rmt]")
 #endif
 
 #if RMT_SUPPORT_TX_LOOP_COUNT
+static void rmt_tx_loop_end(rmt_channel_t channel, void *arg)
+{
+    rmt_tx_stop(channel);
+}
 TEST_CASE("RMT TX loop", "[rmt]")
 {
     RingbufHandle_t rb = NULL;
@@ -476,6 +487,8 @@ TEST_CASE("RMT TX loop", "[rmt]")
 
     vTaskDelay(pdMS_TO_TICKS(1000));
 
+    // register callback functions, invoked when tx loop count to ceiling
+    rmt_register_tx_end_callback(rmt_tx_loop_end, NULL);
     // build NEC codes
     ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
     // Send new key code

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

@@ -138,7 +138,7 @@ When configuring channel in transmit mode, set **tx_config** and the following m
 * Level of the RMT output, when the carrier is applied - **carrier_level**
 * Enable the RMT output if idle - **idle_output_en**
 * Set the signal level on the RMT output if idle - **idle_level**
-
+:esp32s2: * Specify maximum number of transmissions in a loop - **loop_count**
 
 Receive Mode
 ^^^^^^^^^^^^