mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
rmt: better support rx demodulation
This commit is contained in:
parent
c91565d538
commit
855b316045
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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,57 +197,73 @@ 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]);
|
||||
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));
|
||||
// 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));
|
||||
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++;
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(0x30, cmd);
|
||||
rmt_clean_testbench(tx_channel, rx_channel);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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]")
|
||||
{
|
||||
int tx_channel = 0;
|
||||
@ -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
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
Loading…
Reference in New Issue
Block a user