From 9f55712c0312f05f79893fa8d8972b0b7e13df13 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Mar 2022 15:06:29 +0800 Subject: [PATCH 1/2] rmt: document and improve LL driver --- components/hal/esp32/include/hal/rmt_ll.h | 641 +++++++---- components/hal/esp32c3/include/hal/rmt_ll.h | 982 ++++++++++------ components/hal/esp32h2/include/hal/rmt_ll.h | 984 ++++++++++------ components/hal/esp32s2/include/hal/rmt_ll.h | 840 +++++++++----- components/hal/esp32s3/include/hal/rmt_ll.h | 1020 +++++++++++------ components/hal/include/hal/rmt_hal.h | 58 +- components/hal/include/hal/rmt_types.h | 133 +-- components/hal/rmt_hal.c | 48 +- components/soc/esp32/include/soc/rmt_reg.h | 31 +- components/soc/esp32/include/soc/soc_caps.h | 14 +- components/soc/esp32/rmt_periph.c | 18 +- .../esp32c3/include/soc/Kconfig.soc_caps.in | 8 + components/soc/esp32c3/include/soc/rmt_reg.h | 28 +- components/soc/esp32c3/include/soc/soc_caps.h | 22 +- components/soc/esp32c3/rmt_periph.c | 18 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 8 + components/soc/esp32h2/include/soc/rmt_reg.h | 12 +- components/soc/esp32h2/include/soc/soc_caps.h | 22 +- components/soc/esp32h2/rmt_periph.c | 18 +- .../esp32s2/include/soc/Kconfig.soc_caps.in | 8 + components/soc/esp32s2/include/soc/rmt_reg.h | 9 +- components/soc/esp32s2/include/soc/soc_caps.h | 22 +- components/soc/esp32s2/rmt_periph.c | 18 +- .../esp32s3/include/soc/Kconfig.soc_caps.in | 18 +- components/soc/esp32s3/include/soc/rmt_reg.h | 17 +- .../soc/esp32s3/include/soc/rmt_struct.h | 2 +- components/soc/esp32s3/include/soc/soc_caps.h | 26 +- components/soc/esp32s3/rmt_periph.c | 18 +- components/soc/include/soc/rmt_periph.h | 18 +- tools/ci/check_copyright_ignore.txt | 10 - 30 files changed, 3135 insertions(+), 1936 deletions(-) diff --git a/components/hal/esp32/include/hal/rmt_ll.h b/components/hal/esp32/include/hal/rmt_ll.h index a017b2685a..27dacb12e7 100644 --- a/components/hal/esp32/include/hal/rmt_ll.h +++ b/components/hal/esp32/include/hal/rmt_ll.h @@ -3,128 +3,490 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,7], rx_channel = [0,7] + */ + #pragma once +#include #include #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/rmt_struct.h" +#include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct rmt_mem_t { - struct { - uint32_t data32[64]; - } chan[8]; -} rmt_mem_t; -extern rmt_mem_t RMTMEM; +#define RMT_LL_EVENT_TX_DONE(channel) (1 << ((channel) * 3)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 24)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (0) // esp32 doesn't support tx loop count +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) * 3 + 2)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) * 3 + 1)) +#define RMT_LL_EVENT_RX_THRES(channel) (0) // esp32 doesn't support rx wrap +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) * 3 + 2)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_HW_BASE (&RMT) -#define RMT_LL_MEM_BASE (&RMTMEM) +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; -// Note: TX and RX channel number are all index from zero in the LL driver -// i.e. tx_channel belongs to [0,7], and rx_channel belongs to [0,7] - -static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable) +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) { - dev->conf_ch[0].conf0.clk_en = enable; + dev->conf_ch[0].conf0.clk_en = enable; // register clock gating } +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) { dev->conf_ch[0].conf0.mem_pd = enable; // Only conf0 register of channel0 has `mem_pd` } -static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev) -{ - return dev->conf_ch[0].conf0.mem_pd; // Only conf0 register of channel0 has `mem_pd` -} - -static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable) +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) { dev->apb_conf.fifo_mask = enable; } -static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b) +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { - dev->conf_ch[channel].conf1.ref_always_on = src; + (void)divider_integral; + (void)divider_denominator; + (void)divider_numerator; + switch (src) { + case RMT_CLK_SRC_APB: + dev->conf_ch[channel].conf1.ref_always_on = 1; + break; + case RMT_CLK_SRC_REFTICK: + dev->conf_ch[channel].conf1.ref_always_on = 0; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } } -static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ +static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) { - return dev->conf_ch[channel].conf1.ref_always_on; + for (int i = 0; i < 8; i++) { + if (channel_mask & (1 << i)) { + dev->conf_ch[i].conf1.ref_cnt_rst = 1; + } + } } -static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) { - dev->conf_ch[channel].conf1.ref_cnt_rst = 1; -} - -static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - dev->conf_ch[channel].conf1.ref_cnt_rst = 1; + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); } +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->conf_ch[channel].conf1.mem_rd_rst = 1; dev->conf_ch[channel].conf1.mem_rd_rst = 0; + dev->conf_ch[channel].conf1.apb_mem_rst = 1; + dev->conf_ch[channel].conf1.apb_mem_rst = 0; } -static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) -{ - dev->conf_ch[channel].conf1.mem_wr_rst = 1; - dev->conf_ch[channel].conf1.mem_wr_rst = 0; -} - +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) { dev->conf_ch[channel].conf1.tx_start = 1; } -static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) -{ - RMTMEM.chan[channel].data32[0] = 0; - dev->conf_ch[channel].conf1.tx_start = 0; - dev->conf_ch[channel].conf1.mem_rd_rst = 1; - dev->conf_ch[channel].conf1.mem_rd_rst = 0; -} - -static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.rx_en = enable; -} - +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->conf_ch[channel].conf0.mem_size = block_num; } +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->apb_conf.mem_tx_wrap_en = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf1.tx_conti_mode = enable; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->conf_ch[channel].conf1.idle_out_en = enable; + dev->conf_ch[channel].conf1.idle_out_lv = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->tx_lim_ch[channel].limit = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], high, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], low, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf0.carrier_en = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->conf_ch[channel].conf0.carrier_out_lv = level; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + for (int i = 0; i < 8; i++) { + if (channel_mask & (1 << i)) { + dev->conf_ch[i].conf1.ref_cnt_rst = 1; + } + } +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ +static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->conf_ch[channel].conf1.mem_wr_rst = 1; + dev->conf_ch[channel].conf1.mem_wr_rst = 0; + dev->conf_ch[channel].conf1.apb_mem_rst = 1; + dev->conf_ch[channel].conf1.apb_mem_rst = 0; +} + +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf1.rx_en = enable; +} + +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->conf_ch[channel].conf0.mem_size = block_num; } -static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { - return dev->conf_ch[channel].conf0.mem_size; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres, thres); } -static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) { - return dev->conf_ch[channel].conf0.mem_size; + dev->conf_ch[channel].conf1.mem_owner = owner; } -static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); + dev->conf_ch[channel].conf1.rx_filter_en = enable; } -static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return (dev->status_ch[channel] & 0x3FF) - (channel) * 64; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel]; +} + +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel]; } static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) @@ -139,153 +501,53 @@ static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t return div == 0 ? 256 : div; } -static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->apb_conf.mem_tx_wrap_en = enable; -} - -static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres, thres); -} - static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) { return HAL_FORCE_READ_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres); } -static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner) +static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { - dev->conf_ch[channel].conf1.mem_owner = owner; + return dev->conf_ch[channel].conf0.mem_size; } -static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { - return dev->conf_ch[channel].conf1.mem_owner; + return dev->conf_ch[channel].conf0.mem_size; } -static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.tx_conti_mode = enable; -} - -static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.tx_conti_mode; } -static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) { - // RMT on esp32 doesn't support loop count, adding this only for HAL API consistency + if (dev->conf_ch[channel].conf1.ref_always_on) { + return RMT_CLK_SRC_APB; + } + return RMT_CLK_SRC_REFTICK; } -static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.rx_filter_en = enable; -} - -static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres, thres); -} - -static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.idle_out_en = enable; -} - -static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.idle_out_en; } -static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->conf_ch[channel].conf1.idle_out_lv = level; -} - static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.idle_out_lv; } -static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) { - return dev->status_ch[channel]; + // Only conf0 register of channel0 has `mem_pd` + return dev->conf_ch[0].conf0.mem_pd; } -static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) { - return dev->status_ch[channel]; -} - -static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->tx_lim_ch[channel].limit = limit; -} - -static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) -{ - if (enable) { - dev->int_ena.val |= mask; - } else { - dev->int_ena.val &= ~mask; - } -} - -static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3)); - dev->int_ena.val |= (enable << (channel * 3)); -} - -static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 1)); - dev->int_ena.val |= (enable << (channel * 3 + 1)); -} - -static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 2)); - dev->int_ena.val |= (enable << (channel * 3 + 2)); -} - -static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 2)); - dev->int_ena.val |= (enable << (channel * 3 + 2)); -} - -static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel + 24)); - dev->int_ena.val |= (enable << (channel + 24)); -} - -static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3)); -} - -static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 1)); -} - -static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 2)); -} - -static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 2)); -} - -static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 24)); + return dev->conf_ch[channel].conf1.mem_owner; } static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) @@ -322,39 +584,6 @@ static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev) return (status & 0xFF000000) >> 24; } -static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], high, high_ticks); - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], low, low_ticks); -} - -static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->carrier_duty_ch[channel], high); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->carrier_duty_ch[channel], low); -} - -static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf0.carrier_en = enable; -} - -static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->conf_ch[channel].conf0.carrier_out_lv = level; -} - -//Writes items to the specified TX channel memory with the given offset and length. -//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL) -static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const void *data, size_t length_in_words, size_t off) -{ - volatile uint32_t *to = (volatile uint32_t *)&mem->chan[channel].data32[off]; - uint32_t *from = (uint32_t *)data; - while (length_in_words--) { - *to++ = *from++; - } -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/rmt_ll.h b/components/hal/esp32c3/include/hal/rmt_ll.h index 0cec7df6fc..725def5686 100644 --- a/components/hal/esp32c3/include/hal/rmt_ll.h +++ b/components/hal/esp32c3/include/hal/rmt_ll.h @@ -4,89 +4,150 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,1], rx_channel = [0,1] + */ + #pragma once #include #include #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/rmt_struct.h" +#include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct rmt_mem_t { - struct { - uint32_t data32[48]; - } chan[4]; -} rmt_mem_t; -extern rmt_mem_t RMTMEM; +#define RMT_LL_EVENT_TX_DONE(channel) (1 << (channel)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 8)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 12)) +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) + 4)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) + 2)) +#define RMT_LL_EVENT_RX_THRES(channel) (1 << ((channel) + 10)) +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) + 6)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_MAX_LOOP_COUNT (1023)/*!< Max loop count that hardware is supported */ +#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 -#define RMT_LL_HW_BASE (&RMT) -#define RMT_LL_MEM_BASE (&RMTMEM) +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; -// Note: TX and RX channel number are all index from zero in the LL driver -// i.e. tx_channel belongs to [0,2], and rx_channel belongs to [0,2] - -static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable) +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) { dev->sys_conf.clk_en = enable; // register clock gating dev->sys_conf.mem_clk_force_on = enable; // memory clock gating } +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) { dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pd = enable; } -static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev) -{ - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); -} - -static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable) +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) { dev->sys_conf.fifo_mask = enable; } -static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b) +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) + (void)channel; // the source clock is set for all channels + HAL_ASSERT(divider_integral >= 1); dev->sys_conf.sclk_active = 0; - dev->sys_conf.sclk_sel = src; - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, div_num); - dev->sys_conf.sclk_div_a = div_a; - dev->sys_conf.sclk_div_b = div_b; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, divider_integral - 1); + dev->sys_conf.sclk_div_a = divider_numerator; + dev->sys_conf.sclk_div_b = divider_denominator; + switch (src) { + case RMT_CLK_SRC_APB: + dev->sys_conf.sclk_sel = 1; + break; + case RMT_CLK_SRC_FAST_RC: + dev->sys_conf.sclk_sel = 2; + break; + case RMT_CLK_SRC_XTAL: + dev->sys_conf.sclk_sel = 3; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } dev->sys_conf.sclk_active = 1; } -static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) -{ - return dev->sys_conf.sclk_sel; -} - -static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - dev->ref_cnt_rst.val |= (1 << channel); -} +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) { - dev->ref_cnt_rst.val |= channel_mask; + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x03; } -static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) { - dev->ref_cnt_rst.val |= (1 << (channel + 2)); + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_conf[channel], div_cnt, div); } +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->tx_conf[channel].mem_rd_rst = 1; @@ -95,6 +156,269 @@ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->tx_conf[channel].mem_rst = 0; } +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +{ + // update other configuration registers before start transmitting + dev->tx_conf[channel].conf_update = 1; + dev->tx_conf[channel].tx_start = 1; +} + +/** + * @brief Stop transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) +{ + dev->tx_conf[channel].tx_stop = 1; + // stop won't take place until configurations updated + dev->tx_conf[channel].conf_update = 1; +} + +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ +static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) +{ + dev->tx_conf[channel].mem_size = block_num; +} + +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].mem_tx_wrap_en = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].tx_conti_mode = enable; +} + +/** + * @brief Set loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param count TX loop count + */ +static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +{ + HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range"); + dev->tx_lim[channel].tx_loop_num = count; +} + +/** + * @brief Reset loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel) +{ + dev->tx_lim[channel].loop_count_reset = 1; + dev->tx_lim[channel].loop_count_reset = 0; +} + +/** + * @brief Enable loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_lim[channel].tx_loop_cnt_en = enable; +} + +/** + * @brief Enable transmit multiple channels synchronously + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) +{ + dev->tx_sim.en = enable; +} + +/** + * @brief Clear the TX channels synchronous group + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev) +{ + dev->tx_sim.val &= ~(0x03); +} + +/** + * @brief Add TX channels to the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be added to the synchronous group + */ +static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val |= (channel_mask & 0x03); +} + +/** + * @brief Remove TX channels from the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be removed from the synchronous group + */ +static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val &= ~channel_mask; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->tx_conf[channel].idle_out_en = enable; + dev->tx_conf[channel].idle_out_lv = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->tx_lim[channel].limit = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_carrier[channel], high, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_carrier[channel], low, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].carrier_en = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->tx_conf[channel].carrier_out_lv = level; +} + +/** + * @brief Enable to always output carrier signal, regardless of a valid data transmission + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + */ +static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].carrier_eff_en = !enable; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + // write 1 to reset + dev->ref_cnt_rst.val |= ((channel_mask & 0x03) << 2); +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->rx_conf[channel].conf1.mem_wr_rst = 1; @@ -103,34 +427,263 @@ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->rx_conf[channel].conf1.mem_rst = 0; } -static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_conf[channel].conf_update = 1; - dev->tx_conf[channel].tx_start = 1; -} - -static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_conf[channel].tx_stop = 1; - dev->tx_conf[channel].conf_update = 1; -} - +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->rx_conf[channel].conf1.rx_en = enable; + // rx won't be enabled until configurations updated dev->rx_conf[channel].conf1.conf_update = 1; } -static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) -{ - dev->tx_conf[channel].mem_size = block_num; -} - +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->rx_conf[channel].conf0.mem_size = block_num; } +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + dev->rx_conf[channel].conf0.idle_thres = thres; +} + +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) +{ + dev->rx_conf[channel].conf1.mem_owner = owner; +} + +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf1.rx_filter_en = enable; +} + +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf1, rx_filter_thres, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_status[channel].mem_waddr_ex - (channel + 2) * 48; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->rx_lim[channel].rx_lim = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_carrier[channel], high_thres, high_ticks - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_carrier[channel], low_thres, low_ticks - 1); +} + +/** + * @brief Enable demodulating the carrier on RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf0.carrier_en = enable; +} + +/** + * @brief Set on high or low to demodulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param level Which level to demodulate (0=>low level, 1=>high level) + */ +static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->rx_conf[channel].conf0.carrier_out_lv = level; +} + +/** + * @brief Enable RX wrap + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf1.mem_rx_wrap_en = enable; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->tx_status[channel].val; +} + +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_status[channel].val; +} + +static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_conf[channel], div_cnt); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_conf[channel].conf0.idle_thres; +} + static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].mem_size; @@ -141,140 +694,49 @@ static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel return dev->rx_conf[channel].conf0.mem_size; } -static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_conf[channel], div_cnt, div); -} - -static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt, div); -} - -static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->tx_conf[channel], div_cnt); -} - -static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt); -} - -static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].mem_tx_wrap_en = enable; -} - -static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - dev->rx_conf[channel].conf0.idle_thres = thres; -} - -static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) -{ - return dev->rx_conf[channel].conf0.idle_thres; -} - -static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner) -{ - dev->rx_conf[channel].conf1.mem_owner = owner; -} - -static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) -{ - return dev->rx_conf[channel].conf1.mem_owner; -} - -static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].tx_conti_mode = enable; -} - -static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].tx_conti_mode; } -static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) { - dev->tx_lim[channel].tx_loop_num = count; + rmt_clock_source_t clk_src = RMT_CLK_SRC_APB; + switch (dev->sys_conf.sclk_sel) { + case 1: + clk_src = RMT_CLK_SRC_APB; + break; + case 2: + clk_src = RMT_CLK_SRC_FAST_RC; + break; + case 3: + clk_src = RMT_CLK_SRC_XTAL; + break; + } + return clk_src; } -static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_lim[channel].loop_count_reset = 1; - dev->tx_lim[channel].loop_count_reset = 0; -} - -static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_lim[channel].tx_loop_cnt_en = enable; -} - -static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) -{ - dev->tx_sim.en = enable; -} - -static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val |= 1 << channel; -} - -static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val &= ~(1 << channel); -} - -static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf1.rx_filter_en = enable; -} - -static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf1, rx_filter_thres, thres); -} - -static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].idle_out_en = enable; -} - -static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].idle_out_en; } -static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->tx_conf[channel].idle_out_lv = level; -} - static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].idle_out_lv; } -static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) { - return dev->rx_status[channel].val; + // the RTC domain can also power down RMT memory + // so it's probably not enough to detect whether it's powered down or not + // mem_force_pd has higher priority than mem_force_pu + return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); } -static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) { - return dev->tx_status[channel].val; -} - -static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->tx_lim[channel].limit = limit; -} - -static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->rx_lim[channel].rx_lim = limit; + return dev->rx_conf[channel].conf1.mem_owner; } static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) @@ -282,113 +744,6 @@ static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) return dev->rx_lim[channel].rx_lim; } -static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) -{ - if (enable) { - dev->int_ena.val |= mask; - } else { - dev->int_ena.val &= ~mask; - } -} - -static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << channel); - } else { - dev->int_ena.val &= ~(1 << channel); - } -} - -static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 4)); - } else { - dev->int_ena.val &= ~(1 << (channel + 4)); - } -} - -static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 2)); - } else { - dev->int_ena.val &= ~(1 << (channel + 2)); - } -} - -static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 6)); - } else { - dev->int_ena.val &= ~(1 << (channel + 6)); - } -} - -static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 8)); - } else { - dev->int_ena.val &= ~(1 << (channel + 8)); - } -} - -static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 12)); - } else { - dev->int_ena.val &= ~(1 << (channel + 12)); - } -} - -static inline void rmt_ll_enable_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 10)); - } else { - dev->int_ena.val &= ~(1 << (channel + 10)); - } -} - -static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel)); -} - -static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 2)); -} - -static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 4)); -} - -static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 6)); -} - -static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 8)); -} - -static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 12)); -} - -static inline void rmt_ll_clear_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 10)); -} - static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) { return dev->int_st.val & 0x03; @@ -424,79 +779,6 @@ static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev) return (dev->int_st.val >> 12) & 0x03; } -static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - // In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register) - // We take care of the "read-modify-write" procedure by ourselves. - typeof(dev->tx_carrier[0]) reg; - reg.high = high_ticks; - reg.low = low_ticks; - dev->tx_carrier[channel].val = reg.val; -} - -static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - typeof(dev->rx_carrier[0]) reg; - reg.high_thres = high_ticks; - reg.low_thres = low_ticks; - dev->rx_carrier[channel].val = reg.val; -} - -static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_carrier[channel], high); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_carrier[channel], low); -} - -static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_carrier[channel], high_thres); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_carrier[channel], low_thres); -} - -static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].carrier_en = enable; -} - -static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf0.carrier_en = enable; -} - -static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->tx_conf[channel].carrier_out_lv = level; -} - -static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->rx_conf[channel].conf0.carrier_out_lv = level; -} - -// set true, enable carrier in all RMT state (idle, reading, sending) -// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent) -static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].carrier_eff_en = !enable; -} - -//Writes items to the specified TX channel memory with the given offset and length. -//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL) -static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const void *data, size_t length_in_words, size_t off) -{ - volatile uint32_t *to = (volatile uint32_t *)&mem->chan[channel].data32[off]; - uint32_t *from = (uint32_t *)data; - while (length_in_words--) { - *to++ = *from++; - } -} - -static inline void rmt_ll_rx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf1.mem_rx_wrap_en = enable; -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/rmt_ll.h b/components/hal/esp32h2/include/hal/rmt_ll.h index f287050e95..725def5686 100644 --- a/components/hal/esp32h2/include/hal/rmt_ll.h +++ b/components/hal/esp32h2/include/hal/rmt_ll.h @@ -4,89 +4,150 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,1], rx_channel = [0,1] + */ + #pragma once #include #include #include -#include "soc/rmt_struct.h" #include "hal/misc.h" +#include "hal/assert.h" +#include "soc/rmt_struct.h" +#include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct rmt_mem_t { - struct { - uint32_t data32[48]; - } chan[4]; -} rmt_mem_t; -extern rmt_mem_t RMTMEM; +#define RMT_LL_EVENT_TX_DONE(channel) (1 << (channel)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 8)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 12)) +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) + 4)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) + 2)) +#define RMT_LL_EVENT_RX_THRES(channel) (1 << ((channel) + 10)) +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) + 6)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_MAX_LOOP_COUNT (1023)/*!< Max loop count that hardware is supported */ +#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 -#define RMT_LL_HW_BASE (&RMT) -#define RMT_LL_MEM_BASE (&RMTMEM) +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; -// Note: TX and RX channel number are all index from zero in the LL driver -// i.e. tx_channel belongs to [0,2], and rx_channel belongs to [0,2] - -static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable) +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) { dev->sys_conf.clk_en = enable; // register clock gating dev->sys_conf.mem_clk_force_on = enable; // memory clock gating } +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) { dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pd = enable; } -static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev) -{ - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); -} - -static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable) +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) { dev->sys_conf.fifo_mask = enable; } -static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b) +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) + (void)channel; // the source clock is set for all channels + HAL_ASSERT(divider_integral >= 1); dev->sys_conf.sclk_active = 0; - dev->sys_conf.sclk_sel = src; - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, div_num); - dev->sys_conf.sclk_div_a = div_a; - dev->sys_conf.sclk_div_b = div_b; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, divider_integral - 1); + dev->sys_conf.sclk_div_a = divider_numerator; + dev->sys_conf.sclk_div_b = divider_denominator; + switch (src) { + case RMT_CLK_SRC_APB: + dev->sys_conf.sclk_sel = 1; + break; + case RMT_CLK_SRC_FAST_RC: + dev->sys_conf.sclk_sel = 2; + break; + case RMT_CLK_SRC_XTAL: + dev->sys_conf.sclk_sel = 3; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } dev->sys_conf.sclk_active = 1; } -static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) -{ - return dev->sys_conf.sclk_sel; -} - -static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - dev->ref_cnt_rst.val |= (1 << channel); -} +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) { - dev->ref_cnt_rst.val |= channel_mask; + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x03; } -static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) { - dev->ref_cnt_rst.val |= (1 << (channel + 2)); + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_conf[channel], div_cnt, div); } +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->tx_conf[channel].mem_rd_rst = 1; @@ -95,6 +156,269 @@ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->tx_conf[channel].mem_rst = 0; } +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +{ + // update other configuration registers before start transmitting + dev->tx_conf[channel].conf_update = 1; + dev->tx_conf[channel].tx_start = 1; +} + +/** + * @brief Stop transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) +{ + dev->tx_conf[channel].tx_stop = 1; + // stop won't take place until configurations updated + dev->tx_conf[channel].conf_update = 1; +} + +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ +static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) +{ + dev->tx_conf[channel].mem_size = block_num; +} + +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].mem_tx_wrap_en = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].tx_conti_mode = enable; +} + +/** + * @brief Set loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param count TX loop count + */ +static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +{ + HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range"); + dev->tx_lim[channel].tx_loop_num = count; +} + +/** + * @brief Reset loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel) +{ + dev->tx_lim[channel].loop_count_reset = 1; + dev->tx_lim[channel].loop_count_reset = 0; +} + +/** + * @brief Enable loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_lim[channel].tx_loop_cnt_en = enable; +} + +/** + * @brief Enable transmit multiple channels synchronously + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) +{ + dev->tx_sim.en = enable; +} + +/** + * @brief Clear the TX channels synchronous group + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev) +{ + dev->tx_sim.val &= ~(0x03); +} + +/** + * @brief Add TX channels to the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be added to the synchronous group + */ +static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val |= (channel_mask & 0x03); +} + +/** + * @brief Remove TX channels from the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be removed from the synchronous group + */ +static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val &= ~channel_mask; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->tx_conf[channel].idle_out_en = enable; + dev->tx_conf[channel].idle_out_lv = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->tx_lim[channel].limit = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_carrier[channel], high, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_carrier[channel], low, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].carrier_en = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->tx_conf[channel].carrier_out_lv = level; +} + +/** + * @brief Enable to always output carrier signal, regardless of a valid data transmission + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + */ +static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_conf[channel].carrier_eff_en = !enable; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + // write 1 to reset + dev->ref_cnt_rst.val |= ((channel_mask & 0x03) << 2); +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->rx_conf[channel].conf1.mem_wr_rst = 1; @@ -103,34 +427,263 @@ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->rx_conf[channel].conf1.mem_rst = 0; } -static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_conf[channel].conf_update = 1; - dev->tx_conf[channel].tx_start = 1; -} - -static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_conf[channel].tx_stop = 1; - dev->tx_conf[channel].conf_update = 1; -} - +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->rx_conf[channel].conf1.rx_en = enable; + // rx won't be enabled until configurations updated dev->rx_conf[channel].conf1.conf_update = 1; } -static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) -{ - dev->tx_conf[channel].mem_size = block_num; -} - +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->rx_conf[channel].conf0.mem_size = block_num; } +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + dev->rx_conf[channel].conf0.idle_thres = thres; +} + +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) +{ + dev->rx_conf[channel].conf1.mem_owner = owner; +} + +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf1.rx_filter_en = enable; +} + +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf1, rx_filter_thres, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_status[channel].mem_waddr_ex - (channel + 2) * 48; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->rx_lim[channel].rx_lim = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_carrier[channel], high_thres, high_ticks - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_carrier[channel], low_thres, low_ticks - 1); +} + +/** + * @brief Enable demodulating the carrier on RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf0.carrier_en = enable; +} + +/** + * @brief Set on high or low to demodulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param level Which level to demodulate (0=>low level, 1=>high level) + */ +static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->rx_conf[channel].conf0.carrier_out_lv = level; +} + +/** + * @brief Enable RX wrap + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->rx_conf[channel].conf1.mem_rx_wrap_en = enable; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->tx_status[channel].val; +} + +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_status[channel].val; +} + +static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_conf[channel], div_cnt); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) +{ + return dev->rx_conf[channel].conf0.idle_thres; +} + static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].mem_size; @@ -141,140 +694,49 @@ static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel return dev->rx_conf[channel].conf0.mem_size; } -static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_conf[channel], div_cnt, div); -} - -static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt, div); -} - -static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->tx_conf[channel], div_cnt); -} - -static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->rx_conf[channel].conf0, div_cnt); -} - -static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].mem_tx_wrap_en = enable; -} - -static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - dev->rx_conf[channel].conf0.idle_thres = thres; -} - -static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) -{ - return dev->rx_conf[channel].conf0.idle_thres; -} - -static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner) -{ - dev->rx_conf[channel].conf1.mem_owner = owner; -} - -static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) -{ - return dev->rx_conf[channel].conf1.mem_owner; -} - -static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].tx_conti_mode = enable; -} - -static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].tx_conti_mode; } -static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) { - dev->tx_lim[channel].tx_loop_num = count; + rmt_clock_source_t clk_src = RMT_CLK_SRC_APB; + switch (dev->sys_conf.sclk_sel) { + case 1: + clk_src = RMT_CLK_SRC_APB; + break; + case 2: + clk_src = RMT_CLK_SRC_FAST_RC; + break; + case 3: + clk_src = RMT_CLK_SRC_XTAL; + break; + } + return clk_src; } -static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_lim[channel].loop_count_reset = 1; - dev->tx_lim[channel].loop_count_reset = 0; -} - -static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_lim[channel].tx_loop_cnt_en = enable; -} - -static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) -{ - dev->tx_sim.en = enable; -} - -static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val |= 1 << channel; -} - -static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val &= ~(1 << channel); -} - -static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf1.rx_filter_en = enable; -} - -static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rx_conf[channel].conf1, rx_filter_thres, thres); -} - -static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].idle_out_en = enable; -} - -static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].idle_out_en; } -static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->tx_conf[channel].idle_out_lv = level; -} - static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) { return dev->tx_conf[channel].idle_out_lv; } -static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) { - return dev->rx_status[channel].val; + // the RTC domain can also power down RMT memory + // so it's probably not enough to detect whether it's powered down or not + // mem_force_pd has higher priority than mem_force_pu + return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); } -static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) { - return dev->tx_status[channel].val; -} - -static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->tx_lim[channel].limit = limit; -} - -static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->rx_lim[channel].rx_lim = limit; + return dev->rx_conf[channel].conf1.mem_owner; } static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) @@ -282,113 +744,6 @@ static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) return dev->rx_lim[channel].rx_lim; } -static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) -{ - if (enable) { - dev->int_ena.val |= mask; - } else { - dev->int_ena.val &= ~mask; - } -} - -static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << channel); - } else { - dev->int_ena.val &= ~(1 << channel); - } -} - -static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 4)); - } else { - dev->int_ena.val &= ~(1 << (channel + 4)); - } -} - -static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 2)); - } else { - dev->int_ena.val &= ~(1 << (channel + 2)); - } -} - -static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 6)); - } else { - dev->int_ena.val &= ~(1 << (channel + 6)); - } -} - -static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 8)); - } else { - dev->int_ena.val &= ~(1 << (channel + 8)); - } -} - -static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 12)); - } else { - dev->int_ena.val &= ~(1 << (channel + 12)); - } -} - -static inline void rmt_ll_enable_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 10)); - } else { - dev->int_ena.val &= ~(1 << (channel + 10)); - } -} - -static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel)); -} - -static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 2)); -} - -static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 4)); -} - -static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 6)); -} - -static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 8)); -} - -static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 12)); -} - -static inline void rmt_ll_clear_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 10)); -} - static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) { return dev->int_st.val & 0x03; @@ -424,79 +779,6 @@ static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev) return (dev->int_st.val >> 12) & 0x03; } -static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - // In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register) - // We take care of the "read-modify-write" procedure by ourselves. - typeof(dev->tx_carrier[0]) reg; - reg.high = high_ticks; - reg.low = low_ticks; - dev->tx_carrier[channel].val = reg.val; -} - -static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - typeof(dev->rx_carrier[0]) reg; - reg.high_thres = high_ticks; - reg.low_thres = low_ticks; - dev->rx_carrier[channel].val = reg.val; -} - -static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_carrier[channel], high); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->tx_carrier[channel], low); -} - -static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_carrier[channel], high_thres); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->rx_carrier[channel], low_thres); -} - -static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].carrier_en = enable; -} - -static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf0.carrier_en = enable; -} - -static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->tx_conf[channel].carrier_out_lv = level; -} - -static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->rx_conf[channel].conf0.carrier_out_lv = level; -} - -// set true, enable carrier in all RMT state (idle, reading, sending) -// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent) -static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_conf[channel].carrier_eff_en = !enable; -} - -//Writes items to the specified TX channel memory with the given offset and length. -//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL) -static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const void *data, size_t length_in_words, size_t off) -{ - volatile uint32_t *to = (volatile uint32_t *)&mem->chan[channel].data32[off]; - uint32_t *from = (uint32_t *)data; - while (length_in_words--) { - *to++ = *from++; - } -} - -static inline void rmt_ll_rx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->rx_conf[channel].conf1.mem_rx_wrap_en = enable; -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/rmt_ll.h b/components/hal/esp32s2/include/hal/rmt_ll.h index 02e457f3ac..fd5bc82aaf 100644 --- a/components/hal/esp32s2/include/hal/rmt_ll.h +++ b/components/hal/esp32s2/include/hal/rmt_ll.h @@ -4,137 +4,630 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,3], rx_channel = [0,3] + */ + #pragma once +#include #include #include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/rmt_struct.h" +#include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct rmt_mem_t { - struct { - uint32_t data32[64]; - } chan[4]; -} rmt_mem_t; -extern rmt_mem_t RMTMEM; -#define RMT_LL_MAX_LOOP_COUNT (1023)/*!< Max loop count that hardware is supported */ +#define RMT_LL_EVENT_TX_DONE(channel) (1 << ((channel) * 3)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 12)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 16)) +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) * 3 + 2)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) * 3 + 1)) +#define RMT_LL_EVENT_RX_THRES(channel) (0) // esp32s2 doesn't support rx wrap +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) * 3 + 2)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_HW_BASE (&RMT) -#define RMT_LL_MEM_BASE (&RMTMEM) +#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 -// Note: TX and RX channel number are all index from zero in the LL driver -// i.e. tx_channel belongs to [0,3], and rx_channel belongs to [0,3] +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; -static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable) +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) { dev->apb_conf.clk_en = enable; // register clock gating dev->apb_conf.mem_clk_force_on = enable; // memory clock gating } +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) { dev->apb_conf.mem_force_pu = !enable; dev->apb_conf.mem_force_pd = enable; } -static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev) -{ - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->apb_conf.mem_force_pd) || !(dev->apb_conf.mem_force_pu); -} - -static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable) +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) { dev->apb_conf.apb_fifo_mask = enable; } -static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b) +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { - dev->conf_ch[channel].conf1.ref_always_on = src; + (void)divider_integral; + (void)divider_denominator; + (void)divider_numerator; + switch (src) { + case RMT_CLK_SRC_APB: + dev->conf_ch[channel].conf1.ref_always_on = 1; + break; + case RMT_CLK_SRC_REFTICK: + dev->conf_ch[channel].conf1.ref_always_on = 0; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } } -static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) -{ - return dev->conf_ch[channel].conf1.ref_always_on; -} - -static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - dev->ref_cnt_rst.val |= (1 << channel); -} +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) { - dev->ref_cnt_rst.val |= channel_mask; + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x0F; } -static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) { - dev->ref_cnt_rst.val |= (1 << channel); + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); } +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->conf_ch[channel].conf1.mem_rd_rst = 1; dev->conf_ch[channel].conf1.mem_rd_rst = 0; + dev->conf_ch[channel].conf1.apb_mem_rst = 1; + dev->conf_ch[channel].conf1.apb_mem_rst = 0; } -static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) -{ - dev->conf_ch[channel].conf1.mem_wr_rst = 1; - dev->conf_ch[channel].conf1.mem_wr_rst = 0; -} - +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) { dev->conf_ch[channel].conf1.tx_start = 1; } +/** + * @brief Stop transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) { dev->conf_ch[channel].conf1.tx_stop = 1; } -static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.rx_en = enable; -} - +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->conf_ch[channel].conf0.mem_size = block_num; } +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->apb_conf.mem_tx_wrap_en = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf1.tx_conti_mode = enable; +} + +/** + * @brief Set loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param count TX loop count + */ +static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +{ + HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range"); + dev->tx_lim_ch[channel].tx_loop_num = count; +} + +/** + * @brief Reset loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel) +{ + dev->tx_lim_ch[channel].loop_count_reset = 1; + dev->tx_lim_ch[channel].loop_count_reset = 0; +} + +/** + * @brief Enable loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->tx_lim_ch[channel].tx_loop_cnt_en = enable; +} + +/** + * @brief Enable transmit multiple channels synchronously + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) +{ + dev->tx_sim.en = enable; +} + +/** + * @brief Clear the TX channels synchronous group + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev) +{ + dev->tx_sim.val &= ~(0x0F); +} + +/** + * @brief Add TX channels to the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be added to the synchronous group + */ +static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val |= (channel_mask & 0x0F); +} + +/** + * @brief Remove TX channels from the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be removed from the synchronous group + */ +static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val &= ~channel_mask; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->conf_ch[channel].conf1.idle_out_en = enable; + dev->conf_ch[channel].conf1.idle_out_lv = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->tx_lim_ch[channel].tx_lim = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], high, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->carrier_duty_ch[channel], low, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf0.carrier_en = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->conf_ch[channel].conf0.carrier_out_lv = level; +} + +/** + * @brief Enable to always output carrier signal, regardless of a valid data transmission + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + */ +static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf0.carrier_eff_en = !enable; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x0F; +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ +static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->conf_ch[channel].conf1.mem_wr_rst = 1; + dev->conf_ch[channel].conf1.mem_wr_rst = 0; + dev->conf_ch[channel].conf1.apb_mem_rst = 1; + dev->conf_ch[channel].conf1.apb_mem_rst = 0; +} + +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf1.rx_en = enable; +} + +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->conf_ch[channel].conf0.mem_size = block_num; } -static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { - return dev->conf_ch[channel].conf0.mem_size; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres, thres); } -static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) { - return dev->conf_ch[channel].conf0.mem_size; + dev->conf_ch[channel].conf1.mem_owner = owner; } -static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) { - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); + dev->conf_ch[channel].conf1.rx_filter_en = enable; } -static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) { - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel].mem_waddr_ex - (channel) * 64; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ch_rx_carrier_rm[channel], carrier_high_thres_ch, high_ticks - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ch_rx_carrier_rm[channel], carrier_low_thres_ch, low_ticks - 1); +} + +/** + * @brief Enable demodulating the carrier on RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf0.carrier_en = enable; +} + +/** + * @brief Set on high or low to demodulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param level Which level to demodulate (0=>low level, 1=>high level) + */ +static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->conf_ch[channel].conf0.carrier_out_lv = level; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel].val; +} + +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel].val; } static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) @@ -149,190 +642,55 @@ static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t return div == 0 ? 256 : div; } -static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->apb_conf.mem_tx_wrap_en = enable; -} - -static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres, thres); -} - static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) { return HAL_FORCE_READ_U32_REG_FIELD(dev->conf_ch[channel].conf0, idle_thres); } -static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner) +static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { - dev->conf_ch[channel].conf1.mem_owner = owner; + return dev->conf_ch[channel].conf0.mem_size; } -static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { - return dev->conf_ch[channel].conf1.mem_owner; + return dev->conf_ch[channel].conf0.mem_size; } -static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.tx_conti_mode = enable; -} - -static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.tx_conti_mode; } -static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) { - dev->tx_lim_ch[channel].tx_loop_num = count; + if (dev->conf_ch[channel].conf1.ref_always_on) { + return RMT_CLK_SRC_APB; + } + return RMT_CLK_SRC_REFTICK; } -static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_lim_ch[channel].loop_count_reset = 1; - dev->tx_lim_ch[channel].loop_count_reset = 0; -} - -static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->tx_lim_ch[channel].tx_loop_cnt_en = enable; -} - -static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) -{ - dev->tx_sim.en = enable; -} - -static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val |= 1 << channel; -} - -static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val &= ~(1 << channel); -} - -static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.rx_filter_en = enable; -} - -static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf1, rx_filter_thres, thres); -} - -static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf1.idle_out_en = enable; -} - -static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.idle_out_en; } -static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->conf_ch[channel].conf1.idle_out_lv = level; -} - static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) { return dev->conf_ch[channel].conf1.idle_out_lv; } -static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) { - return dev->status_ch[channel].val; + // the RTC domain can also power down RMT memory + // so it's probably not enough to detect whether it's powered down or not + // mem_force_pd has higher priority than mem_force_pu + return (dev->apb_conf.mem_force_pd) || !(dev->apb_conf.mem_force_pu); } -static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) { - return dev->status_ch[channel].val; -} - -static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->tx_lim_ch[channel].tx_lim = limit; -} - -static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) -{ - if (enable) { - dev->int_ena.val |= mask; - } else { - dev->int_ena.val &= ~mask; - } -} - -static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3)); - dev->int_ena.val |= (enable << (channel * 3)); -} - -static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 1)); - dev->int_ena.val |= (enable << (channel * 3 + 1)); -} - -static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 2)); - dev->int_ena.val |= (enable << (channel * 3 + 2)); -} - -static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel * 3 + 2)); - dev->int_ena.val |= (enable << (channel * 3 + 2)); -} - -static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel + 12)); - dev->int_ena.val |= (enable << (channel + 12)); -} - -static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->int_ena.val &= ~(1 << (channel + 16)); - dev->int_ena.val |= (enable << (channel + 16)); -} - -static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3)); -} - -static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 1)); -} - -static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 2)); -} - -static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel * 3 + 2)); -} - -static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 12)); -} - -static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 16)); + return dev->conf_ch[channel].conf1.mem_owner; } static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) @@ -371,74 +729,6 @@ static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev) return (status & 0xF0000) >> 16; } -static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - // In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register) - // We take care of the "read-modify-write" procedure by ourselves. - typeof(dev->carrier_duty_ch[0]) reg; - reg.high = high_ticks; - reg.low = low_ticks; - dev->carrier_duty_ch[channel].val = reg.val; -} - -static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - typeof(dev->ch_rx_carrier_rm[0]) reg; - reg.carrier_high_thres_ch = high_ticks; - reg.carrier_low_thres_ch = low_ticks; - dev->ch_rx_carrier_rm[channel].val = reg.val; -} - -static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->carrier_duty_ch[channel], high); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->carrier_duty_ch[channel], low); -} - -static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->ch_rx_carrier_rm[channel], carrier_high_thres_ch); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->ch_rx_carrier_rm[channel], carrier_low_thres_ch); -} - -static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf0.carrier_en = enable; -} - -static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf0.carrier_en = enable; -} - -static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->conf_ch[channel].conf0.carrier_out_lv = level; -} - -static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->conf_ch[channel].conf0.carrier_out_lv = level; -} - -// set true, enable carrier in all RMT state (idle, reading, sending) -// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent) -static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->conf_ch[channel].conf0.carrier_eff_en = !enable; -} - -//Writes items to the specified TX channel memory with the given offset and length. -//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL) -static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const void *data, size_t length_in_words, size_t off) -{ - volatile uint32_t *to = (volatile uint32_t *)&mem->chan[channel].data32[off]; - uint32_t *from = (uint32_t *)data; - while (length_in_words--) { - *to++ = *from++; - } -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/rmt_ll.h b/components/hal/esp32s3/include/hal/rmt_ll.h index af6242bb2a..4c734473fd 100644 --- a/components/hal/esp32s3/include/hal/rmt_ll.h +++ b/components/hal/esp32s3/include/hal/rmt_ll.h @@ -4,87 +4,150 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @note TX and RX channels are index from 0 in the LL driver, i.e. tx_channel = [0,3], rx_channel = [0,3] + */ + #pragma once -#include +#include #include +#include #include "hal/misc.h" +#include "hal/assert.h" #include "soc/rmt_struct.h" +#include "hal/rmt_types.h" #ifdef __cplusplus extern "C" { #endif -typedef struct rmt_mem_t { - struct { - uint32_t data32[48]; - } chan[8]; -} rmt_mem_t; -extern rmt_mem_t RMTMEM; +#define RMT_LL_EVENT_TX_DONE(channel) (1 << (channel)) +#define RMT_LL_EVENT_TX_THRES(channel) (1 << ((channel) + 8)) +#define RMT_LL_EVENT_TX_LOOP_END(channel) (1 << ((channel) + 12)) +#define RMT_LL_EVENT_TX_ERROR(channel) (1 << ((channel) + 4)) +#define RMT_LL_EVENT_RX_DONE(channel) (1 << ((channel) + 16)) +#define RMT_LL_EVENT_RX_THRES(channel) (1 << ((channel) + 24)) +#define RMT_LL_EVENT_RX_ERROR(channel) (1 << ((channel) + 20)) +#define RMT_LL_EVENT_TX_MASK(channel) (RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_THRES(channel) | RMT_LL_EVENT_TX_LOOP_END(channel)) +#define RMT_LL_EVENT_RX_MASK(channel) (RMT_LL_EVENT_RX_DONE(channel) | RMT_LL_EVENT_RX_THRES(channel)) -#define RMT_LL_MAX_LOOP_COUNT (1023)/*!< Max loop count that hardware is supported */ -#define RMT_LL_HW_BASE (&RMT) -#define RMT_LL_MEM_BASE (&RMTMEM) +#define RMT_LL_MAX_LOOP_COUNT_PER_BATCH 1023 -// Note: TX and RX channel number are all index from zero in the LL driver -// i.e. tx_channel belongs to [0,3], and rx_channel belongs to [0,3] +typedef enum { + RMT_LL_MEM_OWNER_SW = 0, + RMT_LL_MEM_OWNER_HW = 1, +} rmt_ll_mem_owner_t; -static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable) +/** + * @brief Enable clock gate for register and memory + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) { dev->sys_conf.clk_en = enable; // register clock gating dev->sys_conf.mem_clk_force_on = enable; // memory clock gating } +/** + * @brief Power down memory + * + * @param dev Peripheral instance address + * @param enable True to power down, False to power up + */ static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) { dev->sys_conf.mem_force_pu = !enable; dev->sys_conf.mem_force_pd = enable; } -static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev) -{ - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); -} - -static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable) +/** + * @brief Enable APB accessing RMT memory in nonfifo mode + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) { dev->sys_conf.apb_fifo_mask = enable; } -static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b) +/** + * @brief Set clock source and divider for RMT channel group + * + * @param dev Peripheral instance address + * @param channel not used as clock source is set for all channels + * @param src Clock source + * @param divider_integral Integral part of the divider + * @param divider_denominator Denominator part of the divider + * @param divider_numerator Numerator part of the divider + */ +static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) + (void)channel; // the source clock is set for all channels + HAL_ASSERT(divider_integral >= 1); dev->sys_conf.sclk_active = 0; - dev->sys_conf.sclk_sel = src; - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, div_num); - dev->sys_conf.sclk_div_a = div_a; - dev->sys_conf.sclk_div_b = div_b; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sys_conf, sclk_div_num, divider_integral - 1); + dev->sys_conf.sclk_div_a = divider_numerator; + dev->sys_conf.sclk_div_b = divider_denominator; + switch (src) { + case RMT_CLK_SRC_APB: + dev->sys_conf.sclk_sel = 1; + break; + case RMT_CLK_SRC_FAST_RC: + dev->sys_conf.sclk_sel = 2; + break; + case RMT_CLK_SRC_XTAL: + dev->sys_conf.sclk_sel = 3; + break; + default: + HAL_ASSERT(false && "unsupported RMT clock source"); + break; + } dev->sys_conf.sclk_active = 1; } -static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) -{ - return dev->sys_conf.sclk_sel; -} - -static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - dev->ref_cnt_rst.val |= (1 << channel); -} +////////////////////////////////////////TX Channel Specific///////////////////////////////////////////////////////////// +/** + * @brief Reset clock divider for TX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels + */ static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) { - dev->ref_cnt_rst.val |= channel_mask; + // write 1 to reset + dev->ref_cnt_rst.val |= channel_mask & 0x0F; } -static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Set TX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param div Division value + */ +static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) { - dev->ref_cnt_rst.val |= (1 << (channel + 4)); + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_n, div); } +/** + * @brief Reset RMT reading pointer for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->chnconf0[channel].mem_rd_rst_n = 1; @@ -93,6 +156,293 @@ static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->chnconf0[channel].apb_mem_rst_n = 0; } +/** + * @brief Enable DMA access for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + HAL_ASSERT(channel == 3 && "only TX channel 3 has DMA ability"); + dev->chnconf0[channel].dma_access_en_n = enable; +} + +/** + * @brief Start transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +{ + // update other configuration registers before start transmitting + dev->chnconf0[channel].conf_update_n = 1; + dev->chnconf0[channel].tx_start_n = 1; +} + +/** + * @brief Stop transmitting for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) +{ + dev->chnconf0[channel].tx_stop_n = 1; + // stop won't take place until configurations updated + dev->chnconf0[channel].conf_update_n = 1; +} + +/** + * @brief Set memory block number for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param block_num memory block number + */ +static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) +{ + dev->chnconf0[channel].mem_size_n = block_num; +} + +/** + * @brief Enable TX wrap + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].mem_tx_wrap_en_n = enable; +} + +/** + * @brief Enable transmitting in a loop + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].tx_conti_mode_n = enable; +} + +/** + * @brief Set loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param count TX loop count + */ +static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) +{ + HAL_ASSERT(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH && "loop count out of range"); + dev->chn_tx_lim[channel].tx_loop_num_chn = count; +} + +/** + * @brief Reset loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + */ +static inline void rmt_ll_tx_reset_loop_count(rmt_dev_t *dev, uint32_t channel) +{ + dev->chn_tx_lim[channel].loop_count_reset_chn = 1; + dev->chn_tx_lim[channel].loop_count_reset_chn = 0; +} + +/** + * @brief Enable loop count for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chn_tx_lim[channel].tx_loop_cnt_en_chn = enable; +} + +/** + * @brief Enable loop stop at count value automatically + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_loop_autostop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chn_tx_lim[channel].loop_stop_en_chn = enable; +} + +/** + * @brief Enable transmit multiple channels synchronously + * + * @param dev Peripheral instance address + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) +{ + dev->tx_sim.tx_sim_en = enable; +} + +/** + * @brief Clear the TX channels synchronous group + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_tx_clear_sync_group(rmt_dev_t *dev) +{ + dev->tx_sim.val &= ~(0x0F); +} + +/** + * @brief Add TX channels to the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be added to the synchronous group + */ +static inline void rmt_ll_tx_sync_group_add_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val |= (channel_mask & 0x0F); +} + +/** + * @brief Remove TX channels from the synchronous group + * + * @param dev Peripheral instance address + * @param channel_mask Mask of TX channels to be removed from the synchronous group + */ +static inline void rmt_ll_tx_sync_group_remove_channels(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->tx_sim.val &= ~channel_mask; +} + +/** + * @brief Fix the output level when TX channel is in IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level IDLE level (1 => high, 0 => low) + * @param enable True to fix the IDLE level, otherwise the IDLE level is determined by EOF encoder + */ +static inline void rmt_ll_tx_fix_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level, bool enable) +{ + dev->chnconf0[channel].idle_out_en_n = enable; + dev->chnconf0[channel].idle_out_lv_n = level; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->chn_tx_lim[channel].tx_lim_chn = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + // ticks=0 means 65536 in hardware + if (high_ticks >= 65536) { + high_ticks = 0; + } + if (low_ticks >= 65536) { + low_ticks = 0; + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_high_chn, high_ticks); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_low_chn, low_ticks); +} + +/** + * @brief Enable modulating carrier signal to TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].carrier_en_n = enable; +} + +/** + * @brief Set on high or low to modulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param level Which level to modulate on (0=>low level, 1=>high level) + */ +static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->chnconf0[channel].carrier_out_lv_n = level; +} + +/** + * @brief Enable to always output carrier signal, regardless of a valid data transmission + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + */ +static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chnconf0[channel].carrier_eff_en_n = !enable; +} + +////////////////////////////////////////RX Channel Specific///////////////////////////////////////////////////////////// + +/** + * @brief Reset clock divider for RX channels by mask + * + * @param dev Peripheral instance address + * @param channel_mask Mask of RX channels + */ +static inline void rmt_ll_rx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask) +{ + dev->ref_cnt_rst.val |= ((channel_mask & 0x0F) << 4); +} + +/** + * @brief Set RX channel clock divider + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param div Division value + */ +static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) +{ + HAL_ASSERT(div >= 1 && div <= 256 && "divider out of range"); + // limit the maximum divider to 256 + if (div >= 256) { + div = 0; // 0 means 256 division + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_m, div); +} + +/** + * @brief Reset RMT writing pointer for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + */ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) { dev->chmconf[channel].conf1.mem_wr_rst_m = 1; @@ -101,34 +451,276 @@ static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel) dev->chmconf[channel].conf1.apb_mem_rst_m = 0; } -static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +/** + * @brief Enable DMA access for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_dma(rmt_dev_t *dev, uint32_t channel, bool enable) { - dev->chnconf0[channel].conf_update_n = 1; - dev->chnconf0[channel].tx_start_n = 1; -} - -static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) -{ - dev->chnconf0[channel].tx_stop_n = 1; - dev->chnconf0[channel].conf_update_n = 1; + HAL_ASSERT(channel == 3 && "only RX channel 3 has DMA ability"); + dev->chmconf[channel].conf0.dma_access_en_m = enable; } +/** + * @brief Enable receiving for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable) { dev->chmconf[channel].conf1.rx_en_m = enable; + // rx won't be enabled until configurations updated dev->chmconf[channel].conf1.conf_update_m = 1; } -static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) -{ - dev->chnconf0[channel].mem_size_n = block_num; -} - +/** + * @brief Set memory block number for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param block_num memory block number + */ static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num) { dev->chmconf[channel].conf0.mem_size_m = block_num; } +/** + * @brief Set the time length for RX channel before going into IDLE state + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Time length threshold + */ +static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + dev->chmconf[channel].conf0.idle_thres_m = thres; +} + +/** + * @brief Set RMT memory owner for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param owner Memory owner + */ +static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, rmt_ll_mem_owner_t owner) +{ + dev->chmconf[channel].conf1.mem_owner_m = owner; +} + +/** + * @brief Enable filter for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX chanenl number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.rx_filter_en_m = enable; +} + +/** + * @brief Set RX channel filter threshold (i.e. the maximum width of one pulse signal that would be treated as a noise) + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param thres Filter threshold + */ +static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_m, thres); +} + +/** + * @brief Get RMT memory write cursor offset + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return writer offset + */ +static inline uint32_t rmt_ll_rx_get_memory_writer_offset(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmstatus[channel].mem_waddr_ex_m - (channel + 4) * 48; +} + +/** + * @brief Set the amount of RMT symbols that can trigger the limitation interrupt + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param limit Specify the number of symbols + */ +static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->chm_rx_lim[channel].chm_rx_lim_reg = limit; +} + +/** + * @brief Set high and low duration of carrier signal + * + * @param dev dev Peripheral instance address + * @param channel RMT TX channel number + * @param high_ticks Duration of high level + * @param low_ticks Duration of low level + */ +static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) +{ + HAL_ASSERT(high_ticks >= 1 && high_ticks <= 65536 && low_ticks >= 1 && low_ticks <= 65536 && "out of range high/low ticks"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_high_thres_chm, high_ticks - 1); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_low_thres_chm, low_ticks - 1); +} + +/** + * @brief Enable demodulating the carrier on RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf0.carrier_en_m = enable; +} + +/** + * @brief Set on high or low to demodulate the carrier signal + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param level Which level to demodulate (0=>low level, 1=>high level) + */ +static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) +{ + dev->chmconf[channel].conf0.carrier_out_lv_m = level; +} + +/** + * @brief Enable RX wrap + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_rx_enable_wrap(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->chmconf[channel].conf1.mem_rx_wrap_en_m = enable; +} + +//////////////////////////////////////////Interrupt Specific//////////////////////////////////////////////////////////// + +/** + * @brief Enable RMT interrupt for specific event mask + * + * @param dev Peripheral instance address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear RMT interrupt status by mask + * + * @param dev Peripheral instance address + * @param mask Interupt status mask + */ +static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status register address + * + * @param dev Peripheral instance address + * @return Register address + */ +static inline volatile void *rmt_ll_get_interrupt_status_reg(rmt_dev_t *dev) +{ + return &dev->int_st; +} + +/** + * @brief Get interrupt status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt raw status for TX channel + * + * @param dev Peripheral instance address + * @param channel RMT TX channel number + * @return Interrupt raw status + */ +static inline uint32_t rmt_ll_tx_get_interrupt_status_raw(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_raw.val & RMT_LL_EVENT_TX_MASK(channel); +} + +/** + * @brief Get interrupt status for RX channel + * + * @param dev Peripheral instance address + * @param channel RMT RX channel number + * @return Interrupt status + */ +static inline uint32_t rmt_ll_rx_get_interrupt_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->int_st.val & RMT_LL_EVENT_RX_MASK(channel); +} + +//////////////////////////////////////////Deprecated Functions////////////////////////////////////////////////////////// +/////////////////////////////The following functions are only used by the legacy driver///////////////////////////////// +/////////////////////////////They might be removed in the next major release (ESP-IDF 6.0)////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t rmt_ll_tx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chnstatus[channel].val; +} + +static inline uint32_t rmt_ll_rx_get_status_word(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmstatus[channel].val; +} + +static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_n); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) +{ + uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_m); + return div == 0 ? 256 : div; +} + +static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) +{ + return dev->chmconf[channel].conf0.idle_thres_m; +} + static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel) { return dev->chnconf0[channel].mem_size_n; @@ -139,145 +731,49 @@ static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel return dev->chmconf[channel].conf0.mem_size_m; } -static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_n, div); -} - -static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_m, div); -} - -static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->chnconf0[channel], div_cnt_n); -} - -static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel) -{ - return HAL_FORCE_READ_U32_REG_FIELD(dev->chmconf[channel].conf0, div_cnt_m); -} - -static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chnconf0[channel].mem_tx_wrap_en_n = enable; -} - -static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - dev->chmconf[channel].conf0.idle_thres_m = thres; -} - -static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel) -{ - return dev->chmconf[channel].conf0.idle_thres_m; -} - -static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner) -{ - dev->chmconf[channel].conf1.mem_owner_m = owner; -} - -static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) -{ - return dev->chmconf[channel].conf1.mem_owner_m; -} - -static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chnconf0[channel].tx_conti_mode_n = enable; -} - -static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_loop_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->chnconf0[channel].tx_conti_mode_n; } -static inline void rmt_ll_tx_enable_loop_autostop(rmt_dev_t *dev, uint32_t channel, bool enable) +static inline rmt_clock_source_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel) { - dev->chn_tx_lim[channel].loop_stop_en_chn = enable; + rmt_clock_source_t clk_src = RMT_CLK_SRC_APB; + switch (dev->sys_conf.sclk_sel) { + case 1: + clk_src = RMT_CLK_SRC_APB; + break; + case 2: + clk_src = RMT_CLK_SRC_FAST_RC; + break; + case 3: + clk_src = RMT_CLK_SRC_XTAL; + break; + } + return clk_src; } -static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count) -{ - dev->chn_tx_lim[channel].tx_loop_num_chn = count; -} - -static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel) -{ - dev->chn_tx_lim[channel].loop_count_reset_chn = 1; - dev->chn_tx_lim[channel].loop_count_reset_chn = 0; -} - -static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chn_tx_lim[channel].tx_loop_cnt_en_chn = enable; -} - -static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable) -{ - dev->tx_sim.tx_sim_en = enable; -} - -static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val |= 1 << channel; -} - -static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel) -{ - dev->tx_sim.val &= ~(1 << channel); -} - -static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chmconf[channel].conf1.rx_filter_en_m = enable; -} - -static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres) -{ - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->chmconf[channel].conf1, rx_filter_thres_m, thres); -} - -static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chnconf0[channel].idle_out_en_n = enable; -} - -static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_tx_is_idle_enabled(rmt_dev_t *dev, uint32_t channel) { return dev->chnconf0[channel].idle_out_en_n; } -static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->chnconf0[channel].idle_out_lv_n = level; -} - static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel) { return dev->chnconf0[channel].idle_out_lv_n; } -static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) { - return dev->chmstatus[channel].val; + // the RTC domain can also power down RMT memory + // so it's probably not enough to detect whether it's powered down or not + // mem_force_pd has higher priority than mem_force_pu + return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); } -static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel) { - return dev->chnstatus[channel].val; -} - -static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->chn_tx_lim[channel].tx_lim_chn = limit; -} - -static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) -{ - dev->chm_rx_lim[channel].chm_rx_lim_reg = limit; + return dev->chmconf[channel].conf1.mem_owner_m; } static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) @@ -285,113 +781,6 @@ static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel) return dev->chm_rx_lim[channel].chm_rx_lim_reg; } -static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) -{ - if (enable) { - dev->int_ena.val |= mask; - } else { - dev->int_ena.val &= ~mask; - } -} - -static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << channel); - } else { - dev->int_ena.val &= ~(1 << channel); - } -} - -static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 4)); - } else { - dev->int_ena.val &= ~(1 << (channel + 4)); - } -} - -static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 16)); - } else { - dev->int_ena.val &= ~(1 << (channel + 16)); - } -} - -static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 20)); - } else { - dev->int_ena.val &= ~(1 << (channel + 20)); - } -} - -static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 8)); - } else { - dev->int_ena.val &= ~(1 << (channel + 8)); - } -} - -static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 12)); - } else { - dev->int_ena.val &= ~(1 << (channel + 12)); - } -} - -static inline void rmt_ll_enable_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - if (enable) { - dev->int_ena.val |= (1 << (channel + 24)); - } else { - dev->int_ena.val &= ~(1 << (channel + 24)); - } -} - -static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel)); -} - -static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 16)); -} - -static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 4)); -} - -static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 20)); -} - -static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 8)); -} - -static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 12)); -} - -static inline void rmt_ll_clear_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) -{ - dev->int_clr.val = (1 << (channel + 24)); -} - static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev) { return dev->int_st.val & 0x0F; @@ -427,79 +816,6 @@ static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev) return (dev->int_st.val >> 12) & 0x0F; } -static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - // In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register) - // We take care of the "read-modify-write" procedure by ourselves. - rmt_chncarrier_duty_reg_t reg; - reg.carrier_high_chn = high_ticks; - reg.carrier_low_chn = low_ticks; - dev->chncarrier_duty[channel].val = reg.val; -} - -static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks) -{ - rmt_chm_rx_carrier_rm_reg_t reg; - reg.carrier_high_thres_chm = high_ticks; - reg.carrier_low_thres_chm = low_ticks; - dev->chm_rx_carrier_rm[channel].val = reg.val; -} - -static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks ) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_high_chn); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->chncarrier_duty[channel], carrier_low_chn); -} - -static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks) -{ - *high_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_high_thres_chm); - *low_ticks = HAL_FORCE_READ_U32_REG_FIELD(dev->chm_rx_carrier_rm[channel], carrier_low_thres_chm); -} - -static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chnconf0[channel].carrier_en_n = enable; -} - -static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chmconf[channel].conf0.carrier_en_m = enable; -} - -static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->chnconf0[channel].carrier_out_lv_n = level; -} - -static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level) -{ - dev->chmconf[channel].conf0.carrier_out_lv_m = level; -} - -// set true, enable carrier in all RMT state (idle, reading, sending) -// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent) -static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chnconf0[channel].carrier_eff_en_n = !enable; -} - -//Writes items to the specified TX channel memory with the given offset and length. -//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL) -static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const void *data, size_t length_in_words, size_t off) -{ - volatile uint32_t *to = (volatile uint32_t *)&mem->chan[channel].data32[off]; - uint32_t *from = (uint32_t *)data; - while (length_in_words--) { - *to++ = *from++; - } -} - -static inline void rmt_ll_rx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) -{ - dev->chmconf[channel].conf1.mem_rx_wrap_en_m = enable; -} - #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/rmt_hal.h b/components/hal/include/hal/rmt_hal.h index 327bd6fd9c..a591f90800 100644 --- a/components/hal/include/hal/rmt_hal.h +++ b/components/hal/include/hal/rmt_hal.h @@ -3,29 +3,30 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + #pragma once +#include + #ifdef __cplusplus extern "C" { #endif -#include - typedef struct rmt_dev_t *rmt_soc_handle_t; // RMT SOC layer handle -typedef struct rmt_mem_t *rmt_mem_handle_t; // RMT memory handle /** * @brief HAL context type of RMT driver - * */ typedef struct { rmt_soc_handle_t regs; /*!< RMT Register base address */ - rmt_mem_handle_t mem; /*!< RMT Memory base address */ } rmt_hal_context_t; -#define RMT_MEM_OWNER_SW (0) /*!< RMT Memory ownership belongs to software side */ -#define RMT_MEM_OWNER_HW (1) /*!< RMT Memory ownership belongs to hardware side */ - /** * @brief Initialize the RMT HAL driver * @@ -49,47 +50,6 @@ void rmt_hal_tx_channel_reset(rmt_hal_context_t *hal, uint32_t channel); */ void rmt_hal_rx_channel_reset(rmt_hal_context_t *hal, uint32_t channel); -/** - * @brief Set counter clock for RMT channel - * - * @param hal: RMT HAL context - * @param channel: RMT channel number - * @param base_clk_hz: base clock for RMT internal channel (counter clock will divide from it) - * @param counter_clk_hz: target counter clock - */ -void rmt_hal_tx_set_channel_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t counter_clk_hz); - -/** - * @brief Set carrier clock for RMT channel - * - * @param hal: RMT HAL context - * @param channel: RMT channel number - * @param base_clk_hz: base clock for RMT carrier generation (carrier clock will divide from it) - * @param carrier_clk_hz: target carrier clock - * @param carrier_clk_duty: duty ratio of carrier clock - */ -void rmt_hal_set_carrier_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t carrier_clk_hz, float carrier_clk_duty); - -/** - * @brief Set filter threshold for RMT Receive channel - * - * @param hal: RMT HAL context - * @param channel: RMT channel number - * @param base_clk_hz: base clock for RMT receive filter - * @param thres_us: threshold of RMT receive filter, in us - */ -void rmt_hal_set_rx_filter_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us); - -/** - * @brief Set idle threshold for RMT Receive channel - * - * @param hal: RMT HAL context - * @param channel: RMT channel number - * @param base_clk_hz: base clock for RMT receive channel - * @param thres_us: IDLE threshold for RMT receive channel - */ -void rmt_hal_set_rx_idle_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us); - #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/rmt_types.h b/components/hal/include/hal/rmt_types.h index 9669fd4885..fcbef4f544 100644 --- a/components/hal/include/hal/rmt_types.h +++ b/components/hal/include/hal/rmt_types.h @@ -1,126 +1,39 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once -#include "soc/soc_caps.h" - #ifdef __cplusplus extern "C" { #endif /** -* @brief RMT channel ID -* -*/ -typedef enum { - RMT_CHANNEL_0, /*!< RMT channel number 0 */ - RMT_CHANNEL_1, /*!< RMT channel number 1 */ - RMT_CHANNEL_2, /*!< RMT channel number 2 */ - RMT_CHANNEL_3, /*!< RMT channel number 3 */ -#if SOC_RMT_CHANNELS_PER_GROUP > 4 - RMT_CHANNEL_4, /*!< RMT channel number 4 */ - RMT_CHANNEL_5, /*!< RMT channel number 5 */ - RMT_CHANNEL_6, /*!< RMT channel number 6 */ - RMT_CHANNEL_7, /*!< RMT channel number 7 */ -#endif - RMT_CHANNEL_MAX /*!< Number of RMT channels */ -} rmt_channel_t; - -/** - * @brief RMT Internal Memory Owner - * + * @brief RMT group clock source + * @note User should select the clock source based on the power and resolution requirement */ typedef enum { - RMT_MEM_OWNER_TX, /*!< RMT RX mode, RMT transmitter owns the memory block*/ - RMT_MEM_OWNER_RX, /*!< RMT RX mode, RMT receiver owns the memory block*/ - RMT_MEM_OWNER_MAX, -} rmt_mem_owner_t; + RMT_CLK_SRC_NONE, /*!< No clock source is selected */ + RMT_CLK_SRC_REFTICK, /*!< Select REF_TICK as the source clock */ + RMT_CLK_SRC_APB, /*!< Select APB as the source clock */ + RMT_CLK_SRC_FAST_RC, /*!< Select internal fast RC oscillator as the source clock */ + RMT_CLK_SRC_XTAL, /*!< Select XTAL as the source clock */ +} rmt_clock_source_t; /** - * @brief Clock Source of RMT Channel - * + * @brief The layout of RMT symbol stored in memory, which is decided by the hardware design */ -typedef enum { -#if SOC_RMT_SUPPORT_REF_TICK - RMT_BASECLK_REF = 0, /*!< RMT source clock is REF_TICK, 1MHz by default */ -#endif - RMT_BASECLK_APB = 1, /*!< RMT source clock is APB CLK, 80Mhz by default */ -#if SOC_RMT_SUPPORT_XTAL - RMT_BASECLK_XTAL = 3, /*!< RMT source clock is XTAL clock, 40Mhz by default */ -#endif - RMT_BASECLK_MAX, -} rmt_source_clk_t; - -/** - * @brief RMT Data Mode - * - * @note We highly recommended to use MEM mode not FIFO mode since there will be some gotcha in FIFO mode. - * - */ -typedef enum { - RMT_DATA_MODE_FIFO, /*regs = &RMT; - hal->mem = &RMTMEM; } void rmt_hal_tx_channel_reset(rmt_hal_context_t *hal, uint32_t channel) { + rmt_ll_tx_reset_channels_clock_div(hal->regs, 1 << channel); rmt_ll_tx_reset_pointer(hal->regs, channel); - rmt_ll_tx_reset_loop(hal->regs, channel); - rmt_ll_enable_tx_err_interrupt(hal->regs, channel, false); - rmt_ll_enable_tx_end_interrupt(hal->regs, channel, false); - rmt_ll_enable_tx_thres_interrupt(hal->regs, channel, false); - rmt_ll_clear_tx_err_interrupt(hal->regs, channel); - rmt_ll_clear_tx_end_interrupt(hal->regs, channel); - rmt_ll_clear_tx_thres_interrupt(hal->regs, channel); +#if SOC_RMT_SUPPORT_TX_LOOP_COUNT + rmt_ll_tx_reset_loop_count(hal->regs, channel); +#endif // SOC_RMT_SUPPORT_TX_LOOP_COUNT + rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_TX_MASK(channel), false); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_MASK(channel)); } void rmt_hal_rx_channel_reset(rmt_hal_context_t *hal, uint32_t channel) { + rmt_ll_rx_reset_channels_clock_div(hal->regs, 1 << channel); rmt_ll_rx_reset_pointer(hal->regs, channel); - rmt_ll_enable_rx_err_interrupt(hal->regs, channel, false); - rmt_ll_enable_rx_end_interrupt(hal->regs, channel, false); - rmt_ll_clear_rx_err_interrupt(hal->regs, channel); - rmt_ll_clear_rx_end_interrupt(hal->regs, channel); -} - -void rmt_hal_tx_set_channel_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t counter_clk_hz) -{ - rmt_ll_tx_reset_channel_clock_div(hal->regs, channel); - uint32_t counter_div = (base_clk_hz + counter_clk_hz / 2) / counter_clk_hz; - rmt_ll_tx_set_channel_clock_div(hal->regs, channel, counter_div); -} - -void rmt_hal_set_carrier_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t carrier_clk_hz, float carrier_clk_duty) -{ - uint32_t carrier_div = (base_clk_hz + carrier_clk_hz / 2) / carrier_clk_hz; - uint32_t div_high = (uint32_t)(carrier_div * carrier_clk_duty); - uint32_t div_low = carrier_div - div_high; - rmt_ll_tx_set_carrier_high_low_ticks(hal->regs, channel, div_high, div_low); -} - -void rmt_hal_set_rx_filter_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us) -{ - uint32_t thres = (uint32_t)(base_clk_hz / 1e6 * thres_us); - rmt_ll_rx_set_filter_thres(hal->regs, channel, thres); -} - -void rmt_hal_set_rx_idle_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us) -{ - uint32_t thres = (uint32_t)(base_clk_hz / 1e6 * thres_us); - rmt_ll_rx_set_idle_thres(hal->regs, channel, thres); + rmt_ll_enable_interrupt(hal->regs, RMT_LL_EVENT_RX_MASK(channel), false); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_MASK(channel)); } diff --git a/components/soc/esp32/include/soc/rmt_reg.h b/components/soc/esp32/include/soc/rmt_reg.h index 250ab650ab..6496f63452 100644 --- a/components/soc/esp32/include/soc/rmt_reg.h +++ b/components/soc/esp32/include/soc/rmt_reg.h @@ -1,20 +1,16 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _SOC_RMT_REG_H_ -#define _SOC_RMT_REG_H_ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once #include "soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + #define RMT_CH0DATA_REG (DR_REG_RMT_BASE + 0x0000) #define RMT_CH1DATA_REG (DR_REG_RMT_BASE + 0x0004) @@ -2598,5 +2594,6 @@ /* RMT memory block address */ #define RMT_CHANNEL_MEM(i) (DR_REG_RMT_BASE + 0x800 + 64 * 4 * (i)) - -#endif /*_SOC_RMT_REG_H_ */ +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index fa58582e5e..45fcadadac 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -219,13 +219,13 @@ #define SOC_PCNT_THRES_POINT_PER_UNIT (2) /*-------------------------- RMT CAPS ----------------------------------------*/ -#define SOC_RMT_GROUPS (1U) /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP (8) /*!< Number of channels that capable of Transmit in each group */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP (8) /*!< Number of channels that capable of Receive in each group */ -#define SOC_RMT_CHANNELS_PER_GROUP (8) /*!< Total 8 channels */ -#define SOC_RMT_MEM_WORDS_PER_CHANNEL (64) /*!< Each channel owns 64 words memory */ -#define SOC_RMT_SUPPORT_REF_TICK (1) /*!< Support set REF_TICK as the RMT clock source */ -#define SOC_RMT_CHANNEL_CLK_INDEPENDENT (1) /*!< Can select different source clock for each channel */ +#define SOC_RMT_GROUPS 1U /*!< One RMT group */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 8 /*!< Number of channels that capable of Transmit in each group */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 8 /*!< Number of channels that capable of Receive in each group */ +#define SOC_RMT_CHANNELS_PER_GROUP 8 /*!< Total 8 channels */ +#define SOC_RMT_MEM_WORDS_PER_CHANNEL 64 /*!< Each channel owns 64 words memory */ +#define SOC_RMT_SUPPORT_REF_TICK 1 /*!< Support set REF_TICK as the RMT clock source */ +#define SOC_RMT_CHANNEL_CLK_INDEPENDENT 1 /*!< Can select different source clock for each channel */ /*-------------------------- RTCIO CAPS --------------------------------------*/ #define SOC_RTCIO_PIN_COUNT 18 diff --git a/components/soc/esp32/rmt_periph.c b/components/soc/esp32/rmt_periph.c index 48d5ea0b02..1edc67a1ff 100644 --- a/components/soc/esp32/rmt_periph.c +++ b/components/soc/esp32/rmt_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/rmt_periph.h" #include "soc/gpio_sig_map.h" diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index dfb4c59720..a83ad5eeda 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -379,6 +379,10 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y +config SOC_RMT_SUPPORT_TX_ASYNC_STOP + bool + default y + config SOC_RMT_SUPPORT_TX_LOOP_COUNT bool default y @@ -387,6 +391,10 @@ config SOC_RMT_SUPPORT_TX_SYNCHRO bool default y +config SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON + bool + default y + config SOC_RMT_SUPPORT_XTAL bool default y diff --git a/components/soc/esp32c3/include/soc/rmt_reg.h b/components/soc/esp32c3/include/soc/rmt_reg.h index 4a916e99d0..106fc78649 100644 --- a/components/soc/esp32c3/include/soc/rmt_reg.h +++ b/components/soc/esp32c3/include/soc/rmt_reg.h @@ -1,24 +1,16 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _SOC_RMT_REG_H_ -#define _SOC_RMT_REG_H_ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "soc.h" #ifdef __cplusplus extern "C" { #endif -#include "soc.h" + #define RMT_CH0DATA_REG (DR_REG_RMT_BASE + 0x0000) #define RMT_CH1DATA_REG (DR_REG_RMT_BASE + 0x0004) @@ -1138,7 +1130,3 @@ extern "C" { #ifdef __cplusplus } #endif - - - -#endif /*_SOC_RMT_REG_H_ */ diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 8eb55e2645..ee662aa565 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -174,16 +174,18 @@ #define SOC_MPU_REGION_WO_SUPPORTED 0 /*--------------------------- RMT CAPS ---------------------------------------*/ -#define SOC_RMT_GROUPS (1U) /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP (2) /*!< Number of channels that capable of Transmit */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP (2) /*!< Number of channels that capable of Receive */ -#define SOC_RMT_CHANNELS_PER_GROUP (4) /*!< Total 4 channels */ -#define SOC_RMT_MEM_WORDS_PER_CHANNEL (48) /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ -#define SOC_RMT_SUPPORT_RX_PINGPONG (1) /*!< Support Ping-Pong mode on RX path */ -#define SOC_RMT_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_LOOP_COUNT (1) /*!< Support transmit specified number of cycles in loop mode */ -#define SOC_RMT_SUPPORT_TX_SYNCHRO (1) /*!< Support coordinate a group of TX channels to start simultaneously */ -#define SOC_RMT_SUPPORT_XTAL (1) /*!< Support set XTAL clock as the RMT clock source */ +#define SOC_RMT_GROUPS 1U /*!< One RMT group */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Transmit */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Receive */ +#define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ +#define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ +#define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ +#define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ +#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ +#define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ +#define SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON 1 /*!< TX carrier can be modulated all the time */ +#define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */ /*-------------------------- RTC CAPS --------------------------------------*/ #define SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH (128) diff --git a/components/soc/esp32c3/rmt_periph.c b/components/soc/esp32c3/rmt_periph.c index 8405b76487..0369d0f200 100644 --- a/components/soc/esp32c3/rmt_periph.c +++ b/components/soc/esp32c3/rmt_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/rmt_periph.h" #include "soc/gpio_sig_map.h" diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 6011e0c2a7..aff6a42262 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -359,6 +359,10 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y +config SOC_RMT_SUPPORT_TX_ASYNC_STOP + bool + default y + config SOC_RMT_SUPPORT_TX_LOOP_COUNT bool default y @@ -367,6 +371,10 @@ config SOC_RMT_SUPPORT_TX_SYNCHRO bool default y +config SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON + bool + default y + config SOC_RMT_SUPPORT_XTAL bool default y diff --git a/components/soc/esp32h2/include/soc/rmt_reg.h b/components/soc/esp32h2/include/soc/rmt_reg.h index 8b4a5227a8..106fc78649 100644 --- a/components/soc/esp32h2/include/soc/rmt_reg.h +++ b/components/soc/esp32h2/include/soc/rmt_reg.h @@ -1,16 +1,16 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef _SOC_RMT_REG_H_ -#define _SOC_RMT_REG_H_ +#pragma once -#include "soc/soc.h" +#include "soc.h" #ifdef __cplusplus extern "C" { #endif + #define RMT_CH0DATA_REG (DR_REG_RMT_BASE + 0x0000) #define RMT_CH1DATA_REG (DR_REG_RMT_BASE + 0x0004) @@ -1130,7 +1130,3 @@ extern "C" { #ifdef __cplusplus } #endif - - - -#endif /*_SOC_RMT_REG_H_ */ diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index fde2d59e05..85c00c6328 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -185,16 +185,18 @@ #define SOC_MPU_REGION_WO_SUPPORTED 0 /*--------------------------- RMT CAPS ---------------------------------------*/ -#define SOC_RMT_GROUPS (1U) /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP (2) /*!< Number of channels that capable of Transmit */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP (2) /*!< Number of channels that capable of Receive */ -#define SOC_RMT_CHANNELS_PER_GROUP (4) /*!< Total 4 channels */ -#define SOC_RMT_MEM_WORDS_PER_CHANNEL (48) /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ -#define SOC_RMT_SUPPORT_RX_PINGPONG (1) /*!< Support Ping-Pong mode on RX path */ -#define SOC_RMT_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_LOOP_COUNT (1) /*!< Support transmit specified number of cycles in loop mode */ -#define SOC_RMT_SUPPORT_TX_SYNCHRO (1) /*!< Support coordinate a group of TX channels to start simultaneously */ -#define SOC_RMT_SUPPORT_XTAL (1) /*!< Support set XTAL clock as the RMT clock source */ +#define SOC_RMT_GROUPS 1U /*!< One RMT group */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Transmit */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 2 /*!< Number of channels that capable of Receive */ +#define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ +#define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ +#define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ +#define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ +#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ +#define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ +#define SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON 1 /*!< TX carrier can be modulated all the time */ +#define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */ /*-------------------------- RTC CAPS --------------------------------------*/ #define SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH (128) diff --git a/components/soc/esp32h2/rmt_periph.c b/components/soc/esp32h2/rmt_periph.c index 8405b76487..0369d0f200 100644 --- a/components/soc/esp32h2/rmt_periph.c +++ b/components/soc/esp32h2/rmt_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/rmt_periph.h" #include "soc/gpio_sig_map.h" diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index 38d8675fc0..7560b7440c 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -419,6 +419,10 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y +config SOC_RMT_SUPPORT_TX_ASYNC_STOP + bool + default y + config SOC_RMT_SUPPORT_TX_LOOP_COUNT bool default y @@ -427,6 +431,10 @@ config SOC_RMT_SUPPORT_TX_SYNCHRO bool default y +config SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON + bool + default y + config SOC_RMT_SUPPORT_REF_TICK bool default y diff --git a/components/soc/esp32s2/include/soc/rmt_reg.h b/components/soc/esp32s2/include/soc/rmt_reg.h index 8225f6a687..447feda145 100644 --- a/components/soc/esp32s2/include/soc/rmt_reg.h +++ b/components/soc/esp32s2/include/soc/rmt_reg.h @@ -1,12 +1,11 @@ -/** - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +/* + * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD * - * SPDX-License-Identifier: Apache-2.0 + * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include -#include "soc/soc.h" +#include "soc.h" #ifdef __cplusplus extern "C" { diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 338643de57..81230a8f73 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -199,16 +199,18 @@ #define SOC_PCNT_THRES_POINT_PER_UNIT (2) /*-------------------------- RMT CAPS ----------------------------------------*/ -#define SOC_RMT_GROUPS (1U) /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP (4) /*!< Number of channels that capable of Transmit in each group */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP (4) /*!< Number of channels that capable of Receive in each group */ -#define SOC_RMT_CHANNELS_PER_GROUP (4) /*!< Total 4 channels */ -#define SOC_RMT_MEM_WORDS_PER_CHANNEL (64) /*!< Each channel owns 64 words memory (1 word = 4 Bytes) */ -#define SOC_RMT_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_LOOP_COUNT (1) /*!< Support transmiting specified number of cycles in loop mode */ -#define SOC_RMT_SUPPORT_TX_SYNCHRO (1) /*!< Support coordinate a group of TX channels to start simultaneously */ -#define SOC_RMT_SUPPORT_REF_TICK (1) /*!< Support set REF_TICK as the RMT clock source */ -#define SOC_RMT_CHANNEL_CLK_INDEPENDENT (1) /*!< Can select different source clock for each channel */ +#define SOC_RMT_GROUPS 1U /*!< One RMT group */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Transmit in each group */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Receive in each group */ +#define SOC_RMT_CHANNELS_PER_GROUP 4 /*!< Total 4 channels */ +#define SOC_RMT_MEM_WORDS_PER_CHANNEL 64 /*!< Each channel owns 64 words memory (1 word = 4 Bytes) */ +#define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ +#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmiting specified number of cycles in loop mode */ +#define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ +#define SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON 1 /*!< TX carrier can be modulated all the time */ +#define SOC_RMT_SUPPORT_REF_TICK 1 /*!< Support set REF_TICK as the RMT clock source */ +#define SOC_RMT_CHANNEL_CLK_INDEPENDENT 1 /*!< Can select different source clock for each channel */ /*-------------------------- RTCIO CAPS --------------------------------------*/ #define SOC_RTCIO_PIN_COUNT 22 diff --git a/components/soc/esp32s2/rmt_periph.c b/components/soc/esp32s2/rmt_periph.c index 59ddb0613d..395ee27549 100644 --- a/components/soc/esp32s2/rmt_periph.c +++ b/components/soc/esp32s2/rmt_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/rmt_periph.h" #include "soc/gpio_sig_map.h" diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 554aff0f41..2418730113 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -460,8 +460,8 @@ config SOC_PCNT_THRES_POINT_PER_UNIT default 2 config SOC_RMT_GROUPS - bool - default y + int + default 1 config SOC_RMT_TX_CANDIDATES_PER_GROUP int @@ -487,11 +487,15 @@ config SOC_RMT_SUPPORT_RX_DEMODULATION bool default y +config SOC_RMT_SUPPORT_TX_ASYNC_STOP + bool + default y + config SOC_RMT_SUPPORT_TX_LOOP_COUNT bool default y -config SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP +config SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP bool default y @@ -499,10 +503,18 @@ config SOC_RMT_SUPPORT_TX_SYNCHRO bool default y +config SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON + bool + default y + config SOC_RMT_SUPPORT_XTAL bool default y +config SOC_RMT_SUPPORT_DMA + bool + default y + config SOC_LCD_I80_SUPPORTED bool default y diff --git a/components/soc/esp32s3/include/soc/rmt_reg.h b/components/soc/esp32s3/include/soc/rmt_reg.h index 55513e5e97..33f663c0ae 100644 --- a/components/soc/esp32s3/include/soc/rmt_reg.h +++ b/components/soc/esp32s3/include/soc/rmt_reg.h @@ -1,21 +1,12 @@ -/** Copyright 2021 Espressif Systems (Shanghai) PTE LTD +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#include #include "soc/soc.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/components/soc/esp32s3/include/soc/rmt_struct.h b/components/soc/esp32s3/include/soc/rmt_struct.h index 189b8b34bd..6614f01818 100644 --- a/components/soc/esp32s3/include/soc/rmt_struct.h +++ b/components/soc/esp32s3/include/soc/rmt_struct.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 8e489084f1..8e73ca070a 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -174,18 +174,20 @@ #define SOC_PCNT_THRES_POINT_PER_UNIT (2) /*-------------------------- RMT CAPS ----------------------------------------*/ -#define SOC_RMT_GROUPS (1) /*!< One RMT group */ -#define SOC_RMT_TX_CANDIDATES_PER_GROUP (4) /*!< Number of channels that capable of Transmit in each group */ -#define SOC_RMT_RX_CANDIDATES_PER_GROUP (4) /*!< Number of channels that capable of Receive in each group */ -#define SOC_RMT_CHANNELS_PER_GROUP (8) /*!< Total 8 channels */ -#define SOC_RMT_MEM_WORDS_PER_CHANNEL (48) /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ -#define SOC_RMT_SUPPORT_RX_PINGPONG (1) /*!< Support Ping-Pong mode on RX path */ -#define SOC_RMT_SUPPORT_RX_DEMODULATION (1) /*!< Support signal demodulation on RX path (i.e. remove carrier) */ -#define SOC_RMT_SUPPORT_TX_LOOP_COUNT (1) /*!< Support transmit specified number of cycles in loop mode */ -#define SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP (1) /*!< Hardware support of auto-stop in loop mode */ -#define SOC_RMT_SUPPORT_TX_SYNCHRO (1) /*!< Support coordinate a group of TX channels to start simultaneously */ -#define SOC_RMT_SUPPORT_XTAL (1) /*!< Support set XTAL clock as the RMT clock source */ - +#define SOC_RMT_GROUPS 1U /*!< One RMT group */ +#define SOC_RMT_TX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Transmit in each group */ +#define SOC_RMT_RX_CANDIDATES_PER_GROUP 4 /*!< Number of channels that capable of Receive in each group */ +#define SOC_RMT_CHANNELS_PER_GROUP 8 /*!< Total 8 channels */ +#define SOC_RMT_MEM_WORDS_PER_CHANNEL 48 /*!< Each channel owns 48 words memory (1 word = 4 Bytes) */ +#define SOC_RMT_SUPPORT_RX_PINGPONG 1 /*!< Support Ping-Pong mode on RX path */ +#define SOC_RMT_SUPPORT_RX_DEMODULATION 1 /*!< Support signal demodulation on RX path (i.e. remove carrier) */ +#define SOC_RMT_SUPPORT_TX_ASYNC_STOP 1 /*!< Support stop transmission asynchronously */ +#define SOC_RMT_SUPPORT_TX_LOOP_COUNT 1 /*!< Support transmit specified number of cycles in loop mode */ +#define SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP 1 /*!< Hardware support of auto-stop in loop mode */ +#define SOC_RMT_SUPPORT_TX_SYNCHRO 1 /*!< Support coordinate a group of TX channels to start simultaneously */ +#define SOC_RMT_SUPPORT_TX_CARRIER_ALWAYS_ON 1 /*!< TX carrier can be modulated all the time */ +#define SOC_RMT_SUPPORT_XTAL 1 /*!< Support set XTAL clock as the RMT clock source */ +#define SOC_RMT_SUPPORT_DMA 1 /*!< RMT peripheral can connect to DMA channel */ /*-------------------------- LCD CAPS ----------------------------------------*/ /* Notes: On esp32-s3, I80 bus and RGB timing generator can't work at the same time */ diff --git a/components/soc/esp32s3/rmt_periph.c b/components/soc/esp32s3/rmt_periph.c index 4581bd30a7..51a0ef8744 100644 --- a/components/soc/esp32s3/rmt_periph.c +++ b/components/soc/esp32s3/rmt_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/rmt_periph.h" #include "soc/gpio_sig_map.h" diff --git a/components/soc/include/soc/rmt_periph.h b/components/soc/include/soc/rmt_periph.h index 0a2d8e2a9a..bf98c6b0eb 100644 --- a/components/soc/include/soc/rmt_periph.h +++ b/components/soc/include/soc/rmt_periph.h @@ -1,16 +1,8 @@ -// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index b49059cd30..72b71329d6 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -969,7 +969,6 @@ components/hal/include/hal/mcpwm_hal.h components/hal/include/hal/mcpwm_types.h components/hal/include/hal/mpu_hal.h components/hal/include/hal/mpu_types.h -components/hal/include/hal/rmt_types.h components/hal/include/hal/rtc_io_types.h components/hal/include/hal/sdio_slave_hal.h components/hal/include/hal/sdio_slave_ll.h @@ -1324,7 +1323,6 @@ components/soc/esp32/include/soc/mmu.h components/soc/esp32/include/soc/nrx_reg.h components/soc/esp32/include/soc/pid.h components/soc/esp32/include/soc/reset_reasons.h -components/soc/esp32/include/soc/rmt_reg.h components/soc/esp32/include/soc/rtc_cntl_reg.h components/soc/esp32/include/soc/rtc_cntl_struct.h components/soc/esp32/include/soc/rtc_i2c_reg.h @@ -1357,7 +1355,6 @@ components/soc/esp32/include/soc/wdev_reg.h components/soc/esp32/interrupts.c components/soc/esp32/ledc_periph.c components/soc/esp32/mcpwm_periph.c -components/soc/esp32/rmt_periph.c components/soc/esp32/sdio_slave_periph.c components/soc/esp32/sdmmc_periph.c components/soc/esp32/sigmadelta_periph.c @@ -1395,7 +1392,6 @@ components/soc/esp32c3/include/soc/ledc_reg.h components/soc/esp32c3/include/soc/mmu.h components/soc/esp32c3/include/soc/nrx_reg.h components/soc/esp32c3/include/soc/reset_reasons.h -components/soc/esp32c3/include/soc/rmt_reg.h components/soc/esp32c3/include/soc/rtc_cntl_reg.h components/soc/esp32c3/include/soc/rtc_cntl_struct.h components/soc/esp32c3/include/soc/rtc_i2c_reg.h @@ -1425,7 +1421,6 @@ components/soc/esp32c3/include/soc/usb_serial_jtag_struct.h components/soc/esp32c3/include/soc/wdev_reg.h components/soc/esp32c3/interrupts.c components/soc/esp32c3/ledc_periph.c -components/soc/esp32c3/rmt_periph.c components/soc/esp32c3/sigmadelta_periph.c components/soc/esp32c3/spi_periph.c components/soc/esp32c3/uart_periph.c @@ -1473,7 +1468,6 @@ components/soc/esp32h2/include/soc/usb_serial_jtag_reg.h components/soc/esp32h2/include/soc/usb_serial_jtag_struct.h components/soc/esp32h2/include/soc/wdev_reg.h components/soc/esp32h2/ledc_periph.c -components/soc/esp32h2/rmt_periph.c components/soc/esp32h2/sigmadelta_periph.c components/soc/esp32h2/spi_periph.c components/soc/esp32h2/uart_periph.c @@ -1557,7 +1551,6 @@ components/soc/esp32s2/include/soc/usbh_struct.h components/soc/esp32s2/include/soc/wdev_reg.h components/soc/esp32s2/interrupts.c components/soc/esp32s2/ledc_periph.c -components/soc/esp32s2/rmt_periph.c components/soc/esp32s2/sigmadelta_periph.c components/soc/esp32s2/spi_periph.c components/soc/esp32s2/touch_sensor_periph.c @@ -1607,7 +1600,6 @@ components/soc/esp32s3/include/soc/nrx_reg.h components/soc/esp32s3/include/soc/peri_backup_reg.h components/soc/esp32s3/include/soc/peri_backup_struct.h components/soc/esp32s3/include/soc/reset_reasons.h -components/soc/esp32s3/include/soc/rmt_reg.h components/soc/esp32s3/include/soc/rtc_gpio_channel.h components/soc/esp32s3/include/soc/rtc_i2c_reg.h components/soc/esp32s3/include/soc/rtc_i2c_struct.h @@ -1657,7 +1649,6 @@ components/soc/esp32s3/include/soc/world_controller_struct.h components/soc/esp32s3/interrupts.c components/soc/esp32s3/ledc_periph.c components/soc/esp32s3/mcpwm_periph.c -components/soc/esp32s3/rmt_periph.c components/soc/esp32s3/rtc_io_periph.c components/soc/esp32s3/sdio_slave_periph.c components/soc/esp32s3/sdmmc_periph.c @@ -1676,7 +1667,6 @@ components/soc/include/soc/i2c_periph.h components/soc/include/soc/interrupts.h components/soc/include/soc/ledc_periph.h components/soc/include/soc/mcpwm_periph.h -components/soc/include/soc/rmt_periph.h components/soc/include/soc/rtc_cntl_periph.h components/soc/include/soc/rtc_periph.h components/soc/include/soc/sdio_slave_periph.h From 4dfbc9ee7b4346021ab688de278fe287fee701fa Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 1 Mar 2022 16:16:07 +0800 Subject: [PATCH 2/2] rmt: remove deprecated functions --- components/driver/include/driver/rmt.h | 165 ++++++++---- components/driver/rmt.c | 250 +++++++++--------- components/driver/test/test_rmt.c | 2 +- docs/doxygen/Doxyfile | 1 - docs/en/api-reference/peripherals/pcnt.rst | 4 +- docs/en/api-reference/peripherals/rmt.rst | 2 +- docs/en/migration-guides/peripherals.rst | 17 +- .../test_utils/ref_clock_impl_rmt_pcnt.c | 23 +- 8 files changed, 276 insertions(+), 188 deletions(-) diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index a8339e6ae0..8afc98b9fd 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -6,10 +6,6 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #include #include #include "esp_err.h" @@ -19,6 +15,10 @@ extern "C" { #include "freertos/ringbuf.h" #include "hal/rmt_types.h" +#ifdef __cplusplus +extern "C" { +#endif + #define RMT_CHANNEL_FLAGS_AWARE_DFS (1 << 0) /*!< Channel can work during APB clock scaling */ #define RMT_CHANNEL_FLAGS_INVERT_SIG (1 << 1) /*!< Invert RMT signal */ @@ -47,6 +47,117 @@ typedef struct { }; } rmt_item32_t; +/** + * @brief RMT hardware memory layout + */ +typedef struct { + struct { + volatile rmt_item32_t data32[SOC_RMT_MEM_WORDS_PER_CHANNEL]; + } chan[SOC_RMT_CHANNELS_PER_GROUP]; +} rmt_mem_t; + +/** +* @brief RMT channel ID +* +*/ +typedef enum { + RMT_CHANNEL_0, /*!< RMT channel number 0 */ + RMT_CHANNEL_1, /*!< RMT channel number 1 */ + RMT_CHANNEL_2, /*!< RMT channel number 2 */ + RMT_CHANNEL_3, /*!< RMT channel number 3 */ +#if SOC_RMT_CHANNELS_PER_GROUP > 4 + RMT_CHANNEL_4, /*!< RMT channel number 4 */ + RMT_CHANNEL_5, /*!< RMT channel number 5 */ + RMT_CHANNEL_6, /*!< RMT channel number 6 */ + RMT_CHANNEL_7, /*!< RMT channel number 7 */ +#endif + RMT_CHANNEL_MAX /*!< Number of RMT channels */ +} rmt_channel_t; + +/** + * @brief RMT Internal Memory Owner + * + */ +typedef enum { + RMT_MEM_OWNER_TX, /*!< RMT RX mode, RMT transmitter owns the memory block*/ + RMT_MEM_OWNER_RX, /*!< RMT RX mode, RMT receiver owns the memory block*/ + RMT_MEM_OWNER_MAX, +} rmt_mem_owner_t; + +/** + * @brief Clock Source of RMT Channel + * + */ +typedef enum { +#if SOC_RMT_SUPPORT_REF_TICK + RMT_BASECLK_REF = 0, /*!< RMT source clock is REF_TICK, 1MHz by default */ +#endif + RMT_BASECLK_APB = 1, /*!< RMT source clock is APB CLK, 80Mhz by default */ +#if SOC_RMT_SUPPORT_XTAL + RMT_BASECLK_XTAL = 3, /*!< RMT source clock is XTAL clock, 40Mhz by default */ +#endif + RMT_BASECLK_MAX, +} rmt_source_clk_t; + +/** + * @brief RMT Data Mode + * + * @note We highly recommended to use MEM mode not FIFO mode since there will be some gotcha in FIFO mode. + * + */ +typedef enum { + RMT_DATA_MODE_FIFO, /*.peripherals.ld +extern rmt_mem_t RMTMEM; + //Enable RMT module static void rmt_module_enable(void) { @@ -240,7 +243,7 @@ esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool *pd_en) { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - *pd_en = rmt_ll_is_mem_power_down(rmt_contex.hal.regs); + *pd_en = rmt_ll_is_mem_powered_down(rmt_contex.hal.regs); RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -252,16 +255,16 @@ esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst) if (tx_idx_rst) { rmt_ll_tx_reset_pointer(rmt_contex.hal.regs, channel); } - rmt_ll_clear_tx_end_interrupt(rmt_contex.hal.regs, channel); + rmt_ll_clear_interrupt_status(rmt_contex.hal.regs, RMT_LL_EVENT_TX_DONE(channel)); // enable tx end interrupt in non-loop mode - if (!rmt_ll_is_tx_loop_enabled(rmt_contex.hal.regs, channel)) { - rmt_ll_enable_tx_end_interrupt(rmt_contex.hal.regs, channel, true); + if (!rmt_ll_tx_is_loop_enabled(rmt_contex.hal.regs, channel)) { + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_DONE(channel), true); } else { #if SOC_RMT_SUPPORT_TX_LOOP_COUNT - rmt_ll_tx_reset_loop(rmt_contex.hal.regs, channel); + rmt_ll_tx_reset_loop_count(rmt_contex.hal.regs, channel); rmt_ll_tx_enable_loop_count(rmt_contex.hal.regs, channel, true); - rmt_ll_clear_tx_loop_interrupt(rmt_contex.hal.regs, channel); - rmt_ll_enable_tx_loop_interrupt(rmt_contex.hal.regs, channel, true); + rmt_ll_clear_interrupt_status(rmt_contex.hal.regs, RMT_LL_EVENT_TX_LOOP_END(channel)); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_LOOP_END(channel), true); #endif } rmt_ll_tx_start(rmt_contex.hal.regs, channel); @@ -273,12 +276,37 @@ esp_err_t rmt_tx_stop(rmt_channel_t channel) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); +#if SOC_RMT_SUPPORT_TX_ASYNC_STOP rmt_ll_tx_stop(rmt_contex.hal.regs, channel); +#else + // write ending marker to stop the TX channel + RMTMEM.chan[channel].data32[0].val = 0; +#endif rmt_ll_tx_reset_pointer(rmt_contex.hal.regs, channel); RMT_EXIT_CRITICAL(); return ESP_OK; } +#if SOC_RMT_SUPPORT_RX_PINGPONG +esp_err_t rmt_set_rx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh) +{ + ESP_RETURN_ON_FALSE(RMT_IS_RX_CHANNEL(channel) && channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); + if (en) { + uint32_t item_block_len = rmt_ll_rx_get_mem_blocks(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)) * RMT_MEM_ITEM_NUM; + ESP_RETURN_ON_FALSE(evt_thresh <= item_block_len, ESP_ERR_INVALID_ARG, TAG, "RMT EVT THRESH ERR"); + RMT_ENTER_CRITICAL(); + rmt_ll_rx_set_limit(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), evt_thresh); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_THRES(RMT_DECODE_RX_CHANNEL(channel)), true); + RMT_EXIT_CRITICAL(); + } else { + RMT_ENTER_CRITICAL(); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_THRES(RMT_DECODE_RX_CHANNEL(channel)), false); + RMT_EXIT_CRITICAL(); + } + return ESP_OK; +} +#endif + esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst) { ESP_RETURN_ON_FALSE(RMT_IS_RX_CHANNEL(channel) && channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); @@ -287,8 +315,8 @@ esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst) if (rx_idx_rst) { rmt_ll_rx_reset_pointer(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); } - rmt_ll_clear_rx_end_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); - rmt_ll_enable_rx_end_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), true); + rmt_ll_clear_interrupt_status(rmt_contex.hal.regs, RMT_LL_EVENT_RX_DONE(RMT_DECODE_RX_CHANNEL(channel))); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_DONE(RMT_DECODE_RX_CHANNEL(channel)), true); #if SOC_RMT_SUPPORT_RX_PINGPONG const uint32_t item_block_len = rmt_ll_rx_get_mem_blocks(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)) * RMT_MEM_ITEM_NUM; @@ -306,11 +334,11 @@ esp_err_t rmt_rx_stop(rmt_channel_t channel) { ESP_RETURN_ON_FALSE(RMT_IS_RX_CHANNEL(channel) && channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - rmt_ll_enable_rx_end_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), false); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_DONE(RMT_DECODE_RX_CHANNEL(channel)), false); rmt_ll_rx_enable(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), false); rmt_ll_rx_reset_pointer(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); #if SOC_RMT_SUPPORT_RX_PINGPONG - rmt_ll_enable_rx_thres_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), false); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_THRES(RMT_DECODE_RX_CHANNEL(channel)), false); #endif RMT_EXIT_CRITICAL(); return ESP_OK; @@ -367,7 +395,7 @@ esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool *loop_en) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - *loop_en = rmt_ll_is_tx_loop_enabled(rmt_contex.hal.regs, channel); + *loop_en = rmt_ll_tx_is_loop_enabled(rmt_contex.hal.regs, channel); RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -386,8 +414,27 @@ esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk) { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(base_clk < RMT_BASECLK_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_BASECLK_ERROR_STR); + rmt_clock_source_t rmt_clk_src = RMT_CLK_SRC_APB; RMT_ENTER_CRITICAL(); - rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, base_clk, 0, 0, 0); + // the clock type might be different to the one used in LL driver, so simply do a translation here + switch (base_clk) { + case RMT_BASECLK_APB: + rmt_clk_src = RMT_CLK_SRC_APB; + break; +#if SOC_RMT_SUPPORT_REF_TICK + case RMT_BASECLK_REF: + rmt_clk_src = RMT_CLK_SRC_REFTICK; + break; +#endif +#if SOC_RMT_SUPPORT_XTAL + case RMT_BASECLK_XTAL: + rmt_clk_src = RMT_CLK_SRC_XTAL; + break; +#endif + default: + break; + } + rmt_ll_set_group_clock_src(rmt_contex.hal.regs, channel, rmt_clk_src, 1, 0, 0); RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -397,6 +444,23 @@ esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t *src_clk) ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); *src_clk = (rmt_source_clk_t)rmt_ll_get_group_clock_src(rmt_contex.hal.regs, channel); + switch (rmt_ll_get_group_clock_src(rmt_contex.hal.regs, channel)) { + case RMT_CLK_SRC_APB: + *src_clk = RMT_BASECLK_APB; + break; +#if SOC_RMT_SUPPORT_REF_TICK + case RMT_CLK_SRC_REFTICK: + *src_clk = RMT_BASECLK_REF; + break; +#endif +#if SOC_RMT_SUPPORT_XTAL + case RMT_CLK_SRC_XTAL: + *src_clk = RMT_BASECLK_XTAL; + break; +#endif + default: + break; + } RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -406,8 +470,7 @@ esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_l ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); ESP_RETURN_ON_FALSE(level < RMT_IDLE_LEVEL_MAX, ESP_ERR_INVALID_ARG, TAG, "RMT IDLE LEVEL ERR"); RMT_ENTER_CRITICAL(); - rmt_ll_tx_enable_idle(rmt_contex.hal.regs, channel, idle_out_en); - rmt_ll_tx_set_idle_level(rmt_contex.hal.regs, channel, level); + rmt_ll_tx_fix_idle_level(rmt_contex.hal.regs, channel, level, idle_out_en); RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -416,7 +479,7 @@ esp_err_t rmt_get_idle_level(rmt_channel_t channel, bool *idle_out_en, rmt_idle_ { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - *idle_out_en = rmt_ll_is_tx_idle_enabled(rmt_contex.hal.regs, channel); + *idle_out_en = rmt_ll_tx_is_idle_enabled(rmt_contex.hal.regs, channel); *level = rmt_ll_tx_get_idle_level(rmt_contex.hal.regs, channel); RMT_EXIT_CRITICAL(); return ESP_OK; @@ -427,65 +490,31 @@ esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t *status) ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); if (RMT_IS_RX_CHANNEL(channel)) { - *status = rmt_ll_rx_get_channel_status(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); + *status = rmt_ll_rx_get_status_word(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); } else { - *status = rmt_ll_tx_get_channel_status(rmt_contex.hal.regs, channel); + *status = rmt_ll_tx_get_status_word(rmt_contex.hal.regs, channel); } RMT_EXIT_CRITICAL(); return ESP_OK; } -void rmt_set_intr_enable_mask(uint32_t mask) -{ - RMT_ENTER_CRITICAL(); - rmt_ll_enable_interrupt(rmt_contex.hal.regs, mask, true); - RMT_EXIT_CRITICAL(); -} - -void rmt_clr_intr_enable_mask(uint32_t mask) -{ - RMT_ENTER_CRITICAL(); - rmt_ll_enable_interrupt(rmt_contex.hal.regs, mask, false); - RMT_EXIT_CRITICAL(); -} - esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en) { ESP_RETURN_ON_FALSE(RMT_IS_RX_CHANNEL(channel) && channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - rmt_ll_enable_rx_end_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), en); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_DONE(RMT_DECODE_RX_CHANNEL(channel)), en); RMT_EXIT_CRITICAL(); return ESP_OK; } -#if SOC_RMT_SUPPORT_RX_PINGPONG -esp_err_t rmt_set_rx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh) -{ - ESP_RETURN_ON_FALSE(RMT_IS_RX_CHANNEL(channel) && channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); - if (en) { - uint32_t item_block_len = rmt_ll_rx_get_mem_blocks(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)) * RMT_MEM_ITEM_NUM; - ESP_RETURN_ON_FALSE(evt_thresh <= item_block_len, ESP_ERR_INVALID_ARG, TAG, "RMT EVT THRESH ERR"); - RMT_ENTER_CRITICAL(); - rmt_ll_rx_set_limit(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), evt_thresh); - rmt_ll_enable_rx_thres_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), true); - RMT_EXIT_CRITICAL(); - } else { - RMT_ENTER_CRITICAL(); - rmt_ll_enable_rx_thres_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), false); - RMT_EXIT_CRITICAL(); - } - return ESP_OK; -} -#endif - esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en) { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); if (RMT_IS_RX_CHANNEL(channel)) { - rmt_ll_enable_rx_err_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), en); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_ERROR(RMT_DECODE_RX_CHANNEL(channel)), en); } else { - rmt_ll_enable_tx_err_interrupt(rmt_contex.hal.regs, channel, en); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_ERROR(channel), en); } RMT_EXIT_CRITICAL(); return ESP_OK; @@ -495,7 +524,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - rmt_ll_enable_tx_end_interrupt(rmt_contex.hal.regs, channel, en); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_DONE(channel), en); RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -508,11 +537,11 @@ esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_th ESP_RETURN_ON_FALSE(evt_thresh <= item_block_len, ESP_ERR_INVALID_ARG, TAG, "RMT EVT THRESH ERR"); RMT_ENTER_CRITICAL(); rmt_ll_tx_set_limit(rmt_contex.hal.regs, channel, evt_thresh); - rmt_ll_enable_tx_thres_interrupt(rmt_contex.hal.regs, channel, true); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_THRES(channel), true); RMT_EXIT_CRITICAL(); } else { RMT_ENTER_CRITICAL(); - rmt_ll_enable_tx_thres_interrupt(rmt_contex.hal.regs, channel, false); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_THRES(channel), false); RMT_EXIT_CRITICAL(); } return ESP_OK; @@ -538,12 +567,6 @@ esp_err_t rmt_set_gpio(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_n return ESP_OK; } -esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num) -{ - // only for backword compatibility - return rmt_set_gpio(channel, mode, gpio_num, false); -} - static bool rmt_is_channel_number_valid(rmt_channel_t channel, uint8_t mode) { // RX mode @@ -574,22 +597,22 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par } RMT_ENTER_CRITICAL(); - rmt_ll_enable_mem_access(dev, true); + rmt_ll_enable_mem_access_nonfifo(dev, true); if (rmt_param->flags & RMT_CHANNEL_FLAGS_AWARE_DFS) { #if SOC_RMT_SUPPORT_XTAL // clock src: XTAL_CLK rmt_source_clk_hz = rtc_clk_xtal_freq_get() * 1000000; - rmt_ll_set_group_clock_src(dev, channel, RMT_BASECLK_XTAL, 0, 0, 0); + rmt_ll_set_group_clock_src(dev, channel, RMT_CLK_SRC_XTAL, 1, 0, 0); #elif SOC_RMT_SUPPORT_REF_TICK // clock src: REF_CLK rmt_source_clk_hz = REF_CLK_FREQ; - rmt_ll_set_group_clock_src(dev, channel, RMT_BASECLK_REF, 0, 0, 0); + rmt_ll_set_group_clock_src(dev, channel, RMT_CLK_SRC_REFTICK, 1, 0, 0); #endif } else { // clock src: APB_CLK rmt_source_clk_hz = APB_CLK_FREQ; - rmt_ll_set_group_clock_src(dev, channel, RMT_BASECLK_APB, 0, 0, 0); + rmt_ll_set_group_clock_src(dev, channel, RMT_CLK_SRC_APB, 1, 0, 0); } RMT_EXIT_CRITICAL(); @@ -619,10 +642,9 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par } #endif /* always enable tx ping-pong */ - rmt_ll_tx_enable_pingpong(dev, channel, true); + rmt_ll_tx_enable_wrap(dev, channel, true); /*Set idle level */ - rmt_ll_tx_enable_idle(dev, channel, rmt_param->tx_config.idle_output_en); - rmt_ll_tx_set_idle_level(dev, channel, idle_level); + rmt_ll_tx_fix_idle_level(dev, channel, idle_level, rmt_param->tx_config.idle_output_en); /*Set carrier*/ rmt_ll_tx_enable_carrier_modulation(dev, channel, carrier_en); if (carrier_en) { @@ -634,7 +656,6 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par rmt_ll_tx_set_carrier_high_low_ticks(dev, channel, duty_h, duty_l); } else { rmt_ll_tx_set_carrier_level(dev, channel, 0); - rmt_ll_tx_set_carrier_high_low_ticks(dev, channel, 0, 0); } RMT_EXIT_CRITICAL(); @@ -648,7 +669,7 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par rmt_ll_rx_set_channel_clock_div(dev, RMT_DECODE_RX_CHANNEL(channel), clk_div); rmt_ll_rx_set_mem_blocks(dev, RMT_DECODE_RX_CHANNEL(channel), mem_cnt); rmt_ll_rx_reset_pointer(dev, RMT_DECODE_RX_CHANNEL(channel)); - rmt_ll_rx_set_mem_owner(dev, RMT_DECODE_RX_CHANNEL(channel), RMT_MEM_OWNER_HW); + rmt_ll_rx_set_mem_owner(dev, RMT_DECODE_RX_CHANNEL(channel), RMT_LL_MEM_OWNER_HW); /*Set idle threshold*/ rmt_ll_rx_set_idle_thres(dev, RMT_DECODE_RX_CHANNEL(channel), threshold); /* Set RX filter */ @@ -657,7 +678,7 @@ static esp_err_t rmt_internal_config(rmt_dev_t *dev, const rmt_config_t *rmt_par #if SOC_RMT_SUPPORT_RX_PINGPONG /* always enable rx ping-pong */ - rmt_ll_rx_enable_pingpong(dev, RMT_DECODE_RX_CHANNEL(channel), true); + rmt_ll_rx_enable_wrap(dev, RMT_DECODE_RX_CHANNEL(channel), true); #endif #if SOC_RMT_SUPPORT_RX_DEMODULATION @@ -692,9 +713,11 @@ esp_err_t rmt_config(const rmt_config_t *rmt_param) static void IRAM_ATTR rmt_fill_memory(rmt_channel_t channel, const rmt_item32_t *item, uint16_t item_num, uint16_t mem_offset) { - RMT_ENTER_CRITICAL(); - rmt_ll_write_memory(rmt_contex.hal.mem, channel, item, item_num, mem_offset); - RMT_EXIT_CRITICAL(); + volatile uint32_t *to = (volatile uint32_t *)&RMTMEM.chan[channel].data32[mem_offset].val; + uint32_t *from = (uint32_t *)item; + while (item_num--) { + *to++ = *from++; + } } esp_err_t rmt_fill_tx_items(rmt_channel_t channel, const rmt_item32_t *item, uint16_t item_num, uint16_t mem_offset) @@ -766,7 +789,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) rmt_contex.rmt_tx_end_callback.function(channel, rmt_contex.rmt_tx_end_callback.arg); } } - rmt_ll_clear_tx_end_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_DONE(channel)); } // Tx thres interrupt @@ -801,11 +824,11 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) p_rmt->tx_len_rem -= p_rmt->tx_sub_len; } else if (len_rem == 0) { rmt_item32_t stop_data = {0}; - rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, p_rmt->tx_offset); + rmt_fill_memory(channel, &stop_data, 1, p_rmt->tx_offset); } else { rmt_fill_memory(channel, pdata, len_rem, p_rmt->tx_offset); rmt_item32_t stop_data = {0}; - rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, p_rmt->tx_offset + len_rem); + rmt_fill_memory(channel, &stop_data, 1, p_rmt->tx_offset + len_rem); p_rmt->tx_data += len_rem; p_rmt->tx_len_rem -= len_rem; } @@ -815,7 +838,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) p_rmt->tx_offset = 0; } } - rmt_ll_clear_tx_thres_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_THRES(channel)); } // Rx end interrupt @@ -827,7 +850,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) if (p_rmt) { rmt_ll_rx_enable(rmt_contex.hal.regs, channel, false); int item_len = rmt_rx_get_mem_len_in_isr(channel); - rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_MEM_OWNER_SW); + rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_LL_MEM_OWNER_SW); if (p_rmt->rx_buf) { addr = (rmt_item32_t *)RMTMEM.chan[RMT_ENCODE_RX_CHANNEL(channel)].data32; #if SOC_RMT_SUPPORT_RX_PINGPONG @@ -853,10 +876,10 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) memset((void *)p_rmt->rx_item_buf, 0, p_rmt->rx_item_buf_size); #endif rmt_ll_rx_reset_pointer(rmt_contex.hal.regs, channel); - rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_MEM_OWNER_HW); + rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_LL_MEM_OWNER_HW); rmt_ll_rx_enable(rmt_contex.hal.regs, channel, true); } - rmt_ll_clear_rx_end_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_DONE(channel)); } #if SOC_RMT_SUPPORT_RX_PINGPONG @@ -870,9 +893,9 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) int rx_thres_lim = rmt_ll_rx_get_limit(rmt_contex.hal.regs, channel); int item_len = (p_rmt->rx_item_start_idx == 0) ? rx_thres_lim : (mem_item_size - rx_thres_lim); if ((p_rmt->rx_item_len + item_len) < (p_rmt->rx_item_buf_size / 4)) { - rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_MEM_OWNER_SW); + rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_LL_MEM_OWNER_SW); memcpy((void *)(p_rmt->rx_item_buf + p_rmt->rx_item_len), (void *)(RMTMEM.chan[RMT_ENCODE_RX_CHANNEL(channel)].data32 + p_rmt->rx_item_start_idx), item_len * 4); - rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_MEM_OWNER_HW); + rmt_ll_rx_set_mem_owner(rmt_contex.hal.regs, channel, RMT_LL_MEM_OWNER_HW); p_rmt->rx_item_len += item_len; p_rmt->rx_item_start_idx += item_len; if (p_rmt->rx_item_start_idx >= mem_item_size) { @@ -881,7 +904,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) } else { ESP_EARLY_LOGE(TAG, "---RX buffer too small: %d", sizeof(p_rmt->rx_item_buf)); } - rmt_ll_clear_rx_thres_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_THRES(channel)); } #endif @@ -894,7 +917,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) rmt_obj_t *p_rmt = p_rmt_obj[channel]; if (p_rmt) { if (p_rmt->loop_autostop) { -#ifndef SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP +#ifndef SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP // hardware doesn't support automatically stop output so driver should stop output here (possibility already overshotted several us) rmt_ll_tx_stop(rmt_contex.hal.regs, channel); rmt_ll_tx_reset_pointer(rmt_contex.hal.regs, channel); @@ -905,7 +928,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) rmt_contex.rmt_tx_end_callback.function(channel, rmt_contex.rmt_tx_end_callback.arg); } } - rmt_ll_clear_tx_loop_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_LOOP_END(channel)); } #endif @@ -919,9 +942,9 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) // Reset the receiver's write/read addresses to prevent endless err interrupts. rmt_ll_rx_reset_pointer(rmt_contex.hal.regs, channel); ESP_EARLY_LOGD(TAG, "RMT RX channel %d error", channel); - ESP_EARLY_LOGD(TAG, "status: 0x%08x", rmt_ll_rx_get_channel_status(rmt_contex.hal.regs, channel)); + ESP_EARLY_LOGD(TAG, "status: 0x%08x", rmt_ll_rx_get_status_word(rmt_contex.hal.regs, channel)); } - rmt_ll_clear_rx_err_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_RX_ERROR(channel)); } // TX Err interrupt @@ -934,9 +957,9 @@ static void IRAM_ATTR rmt_driver_isr_default(void *arg) // Reset the transmitter's write/read addresses to prevent endless err interrupts. rmt_ll_tx_reset_pointer(rmt_contex.hal.regs, channel); ESP_EARLY_LOGD(TAG, "RMT TX channel %d error", channel); - ESP_EARLY_LOGD(TAG, "status: 0x%08x", rmt_ll_tx_get_channel_status(rmt_contex.hal.regs, channel)); + ESP_EARLY_LOGD(TAG, "status: 0x%08x", rmt_ll_tx_get_status_word(rmt_contex.hal.regs, channel)); } - rmt_ll_clear_tx_err_interrupt(hal->regs, channel); + rmt_ll_clear_interrupt_status(hal->regs, RMT_LL_EVENT_TX_ERROR(channel)); } if (HPTaskAwoken == pdTRUE) { @@ -960,15 +983,13 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel) RMT_ENTER_CRITICAL(); // check channel's working mode if (p_rmt_obj[channel]->rx_buf) { - rmt_ll_enable_rx_end_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), 0); - rmt_ll_enable_rx_err_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), 0); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_DONE(RMT_DECODE_RX_CHANNEL(channel)), false); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_ERROR(RMT_DECODE_RX_CHANNEL(channel)), false); #if SOC_RMT_SUPPORT_RX_PINGPONG - rmt_ll_enable_rx_thres_interrupt(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel), 0); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_RX_THRES(RMT_DECODE_RX_CHANNEL(channel)), false); #endif } else { - rmt_ll_enable_tx_end_interrupt(rmt_contex.hal.regs, channel, 0); - rmt_ll_enable_tx_err_interrupt(rmt_contex.hal.regs, channel, 0); - rmt_ll_enable_tx_thres_interrupt(rmt_contex.hal.regs, channel, false); + rmt_ll_enable_interrupt(rmt_contex.hal.regs, RMT_LL_EVENT_TX_DONE(channel) | RMT_LL_EVENT_TX_ERROR(channel) | RMT_LL_EVENT_TX_THRES(channel), false); } RMT_EXIT_CRITICAL(); @@ -1141,14 +1162,14 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t *rmt_item, i } else { rmt_fill_memory(channel, rmt_item, len_rem, 0); rmt_item32_t stop_data = {0}; - rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, len_rem); + rmt_fill_memory(channel, &stop_data, 1, len_rem); p_rmt->tx_len_rem = 0; } rmt_tx_start(channel, true); p_rmt->wait_done = wait_tx_done; if (wait_tx_done) { // wait loop done - if (rmt_ll_is_tx_loop_enabled(rmt_contex.hal.regs, channel)) { + if (rmt_ll_tx_is_loop_enabled(rmt_contex.hal.regs, channel)) { #if SOC_RMT_SUPPORT_TX_LOOP_COUNT xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY); xSemaphoreGive(p_rmt->tx_sem); @@ -1277,7 +1298,7 @@ esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src p_rmt->translator = true; } else { rmt_item32_t stop_data = {0}; - rmt_ll_write_memory(rmt_contex.hal.mem, channel, &stop_data, 1, p_rmt->tx_len_rem); + rmt_fill_memory(channel, &stop_data, 1, p_rmt->tx_len_rem); p_rmt->tx_len_rem = 0; p_rmt->sample_cur = NULL; p_rmt->translator = false; @@ -1337,7 +1358,7 @@ esp_err_t rmt_add_channel_to_group(rmt_channel_t channel) RMT_ENTER_CRITICAL(); rmt_ll_tx_enable_sync(rmt_contex.hal.regs, true); rmt_contex.synchro_channel_mask |= (1 << channel); - rmt_ll_tx_add_to_sync_group(rmt_contex.hal.regs, channel); + rmt_ll_tx_sync_group_add_channels(rmt_contex.hal.regs, 1 << channel); rmt_ll_tx_reset_channels_clock_div(rmt_contex.hal.regs, rmt_contex.synchro_channel_mask); RMT_EXIT_CRITICAL(); return ESP_OK; @@ -1348,7 +1369,7 @@ esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel) ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); rmt_contex.synchro_channel_mask &= ~(1 << channel); - rmt_ll_tx_remove_from_sync_group(rmt_contex.hal.regs, channel); + rmt_ll_tx_sync_group_remove_channels(rmt_contex.hal.regs, 1 << channel); if (rmt_contex.synchro_channel_mask == 0) { rmt_ll_tx_enable_sync(rmt_contex.hal.regs, false); } @@ -1357,24 +1378,11 @@ esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel) } #endif -esp_err_t rmt_memory_rw_rst(rmt_channel_t channel) -{ - ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); - RMT_ENTER_CRITICAL(); - if (RMT_IS_RX_CHANNEL(channel)) { - rmt_ll_rx_reset_pointer(rmt_contex.hal.regs, RMT_DECODE_RX_CHANNEL(channel)); - } else { - rmt_ll_tx_reset_pointer(rmt_contex.hal.regs, channel); - } - RMT_EXIT_CRITICAL(); - return ESP_OK; -} - #if SOC_RMT_SUPPORT_TX_LOOP_COUNT esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); - ESP_RETURN_ON_FALSE(count <= RMT_LL_MAX_LOOP_COUNT, ESP_ERR_INVALID_ARG, TAG, "Invalid count value"); + ESP_RETURN_ON_FALSE(count <= RMT_LL_MAX_LOOP_COUNT_PER_BATCH, ESP_ERR_INVALID_ARG, TAG, "Invalid count value"); RMT_ENTER_CRITICAL(); rmt_ll_tx_set_loop_count(rmt_contex.hal.regs, channel, count); RMT_EXIT_CRITICAL(); @@ -1385,7 +1393,7 @@ esp_err_t rmt_enable_tx_loop_autostop(rmt_channel_t channel, bool en) { ESP_RETURN_ON_FALSE(RMT_IS_TX_CHANNEL(channel), ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); p_rmt_obj[channel]->loop_autostop = en; -#if SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP +#if SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP RMT_ENTER_CRITICAL(); rmt_ll_tx_enable_loop_autostop(rmt_contex.hal.regs, channel, en); RMT_EXIT_CRITICAL(); diff --git a/components/driver/test/test_rmt.c b/components/driver/test/test_rmt.c index e8abac50d9..aeff44a124 100644 --- a/components/driver/test/test_rmt.c +++ b/components/driver/test/test_rmt.c @@ -164,7 +164,7 @@ TEST_CASE("RMT miscellaneous functions", "[rmt]") #endif - TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 1, 0, 1)); + TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 10, 10, 1)); TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0)); rmt_clean_testbench(channel, -1); diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 07be051373..fa03ed338e 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -184,7 +184,6 @@ INPUT = \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_crc.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_mac.h \ $(PROJECT_PATH)/components/esp_system/include/esp_freertos_hooks.h \ - $(PROJECT_PATH)/components/esp_system/include/esp_ipc.h \ $(PROJECT_PATH)/components/esp_system/include/esp_expression_with_stack.h \ $(PROJECT_PATH)/components/app_update/include/esp_ota_ops.h \ $(PROJECT_PATH)/components/esp_https_ota/include/esp_https_ota.h \ diff --git a/docs/en/api-reference/peripherals/pcnt.rst b/docs/en/api-reference/peripherals/pcnt.rst index f819ef512e..9b85513a9b 100644 --- a/docs/en/api-reference/peripherals/pcnt.rst +++ b/docs/en/api-reference/peripherals/pcnt.rst @@ -20,7 +20,7 @@ Functional Overview Description of the PCNT functionality is broken down into the following sections: -- `Resource Allocation <#resource-allocation>`__ covers how to allocate PCNT units and channels with properly set of configurations. It also covers how to recycle the resources when they finished working. +- `Resource Allocation <#resource-allocation>`__ - covers how to allocate PCNT units and channels with properly set of configurations. It also covers how to recycle the resources when they finished working. - `Set Up Channel Actions <#set-up-channel-actions>`__ - covers how to configure the PCNT channel to behave on different signal edges and levels. - `Watch Points <#watch-points>`__ - describes how to configure PCNT watch points (i.e., tell PCNT unit to trigger an event when the count reaches a certain value). @@ -230,7 +230,7 @@ Thread Safety ^^^^^^^^^^^^^ The factory function :cpp:func:`pcnt_new_unit` and :cpp:func:`pcnt_new_channel` are guaranteed to be thread safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks. -Other functions that take the :cpp:type:`pcnt_unit_handle_t` and :cpp:type:`pcnt_channel_handle_t` as the first positional parameter, are not thread safe. The lifecycle of the PCNT unit and channel handle is maintained by the user. So user should avoid calling them concurrently. If it has to, another mutex should be added to prevent the them being accessed concurrently. +Other functions that take the :cpp:type:`pcnt_unit_handle_t` and :cpp:type:`pcnt_channel_handle_t` as the first positional parameter, are not thread safe. The lifecycle of the PCNT unit and channel handle is maintained by the user. So user should avoid calling them concurrently. If it has to, another mutex should be added to prevent them being accessed concurrently. Kconfig Options ^^^^^^^^^^^^^^^ diff --git a/docs/en/api-reference/peripherals/rmt.rst b/docs/en/api-reference/peripherals/rmt.rst index 7495ebcee5..01e98bfd54 100644 --- a/docs/en/api-reference/peripherals/rmt.rst +++ b/docs/en/api-reference/peripherals/rmt.rst @@ -264,7 +264,7 @@ Transmit Mode Parameters .. only:: SOC_RMT_SUPPORT_TX_LOOP_COUNT * Enable or disable loop count feature to automatically transmit items for N iterations, then trigger an ISR callback - :cpp:func:`rmt_set_tx_loop_count` - * Enable automatically stopping when the number of iterations matches the set loop count. Note this is not reliable for target that doesn't support `SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP`. - :cpp:func:`rmt_enable_tx_loop_autostop` + * Enable automatically stopping when the number of iterations matches the set loop count. Note this is not reliable for target that doesn't support `SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP`. - :cpp:func:`rmt_enable_tx_loop_autostop` Receive Mode Parameters diff --git a/docs/en/migration-guides/peripherals.rst b/docs/en/migration-guides/peripherals.rst index 711ef8bd75..58cb0a342b 100644 --- a/docs/en/migration-guides/peripherals.rst +++ b/docs/en/migration-guides/peripherals.rst @@ -102,7 +102,16 @@ I2C Temperature Sensor Driver ------------------------- - 1. Old API header ``temp_sensor.h`` has been redesigned as ``temperature_sensor.h``, it is recommended to use the new driver and the old driver is not allowed to be used at the same time. - 2. Although it's recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/temp_sensor.h``. However, by default, including ``driver/temp_sensor.h`` will bring a build warning like "legacy temperature sensor driver is deprecated, please migrate to driver/temperature_sensor.h". The warning can be suppressed by enabling the menuconfig option :ref:`CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN`. - 3. Configuration contents has been changed. In old version, user need to configure the ``clk_div`` and ``dac_offset``. While in new version, user only need to choose ``tsens_range`` - 4. The process of using temperature sensor has been changed. In old version, user can use ``config->start->read_celsius`` to get value. In the new version, user must install the temperature sensor driver firstly, by ``temperature_sensor_install`` and uninstall it when finished. For more information, you can refer to :doc:`Temperature Sensor <../api-reference/peripherals/temp_sensor>` . + - Old API header ``temp_sensor.h`` has been redesigned as ``temperature_sensor.h``, it is recommended to use the new driver and the old driver is not allowed to be used at the same time. + - Although it's recommended to use the new driver APIs, the legacy driver is still available in the previous include path ``driver/temp_sensor.h``. However, by default, including ``driver/temp_sensor.h`` will bring a build warning like "legacy temperature sensor driver is deprecated, please migrate to driver/temperature_sensor.h". The warning can be suppressed by enabling the menuconfig option :ref:`CONFIG_TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN`. + - Configuration contents has been changed. In old version, user need to configure the ``clk_div`` and ``dac_offset``. While in new version, user only need to choose ``tsens_range`` + - The process of using temperature sensor has been changed. In old version, user can use ``config->start->read_celsius`` to get value. In the new version, user must install the temperature sensor driver firstly, by ``temperature_sensor_install`` and uninstall it when finished. For more information, you can refer to :doc:`Temperature Sensor <../api-reference/peripherals/temp_sensor>` . + +.. only:: SOC_RMT_SUPPORTED + + RMT Driver + ---------- + + - ``rmt_set_intr_enable_mask`` and ``rmt_clr_intr_enable_mask`` are removed, as the interrupt is handled by the driver, user doesn't need to take care of it. + - ``rmt_set_pin`` is removed, as ``rmt_set_gpio`` can do the same thing. + - ``rmt_memory_rw_rst`` is removed, user can use ``rmt_tx_memory_reset`` and ``rmt_rx_memory_reset`` for TX and RX channel respectively. diff --git a/tools/unit-test-app/components/test_utils/ref_clock_impl_rmt_pcnt.c b/tools/unit-test-app/components/test_utils/ref_clock_impl_rmt_pcnt.c index 3afd31d796..78a97375e5 100644 --- a/tools/unit-test-app/components/test_utils/ref_clock_impl_rmt_pcnt.c +++ b/tools/unit-test-app/components/test_utils/ref_clock_impl_rmt_pcnt.c @@ -36,16 +36,22 @@ #include "esp_rom_gpio.h" #include "esp_rom_sys.h" +#if !CONFIG_IDF_TARGET_ESP32 +#error "RMT+PCNT timestamp workaround is only for ESP32" +#endif + #define REF_CLOCK_RMT_CHANNEL 0 // RMT channel 0 #define REF_CLOCK_GPIO 21 // GPIO used to combine RMT out signal with PCNT input signal #define REF_CLOCK_PRESCALER_MS 30 // PCNT high threshold interrupt fired every 30ms - static rmt_hal_context_t s_rmt_hal; static pcnt_unit_handle_t s_pcnt_unit; static pcnt_channel_handle_t s_pcnt_chan; static volatile uint32_t s_milliseconds; +// RMTMEM address is declared in .peripherals.ld +extern rmt_mem_t RMTMEM; + static bool on_reach_watch_point(pcnt_unit_handle_t unit, pcnt_watch_event_data_t *edata, void *user_ctx) { s_milliseconds += REF_CLOCK_PRESCALER_MS; @@ -94,18 +100,17 @@ void ref_clock_init(void) .level1 = 0 }; - rmt_ll_enable_drive_clock(s_rmt_hal.regs, true); - rmt_ll_set_group_clock_src(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, RMT_BASECLK_REF, 0, 0, 0); // select REF_TICK (1MHz) - rmt_hal_tx_set_channel_clock(&s_rmt_hal, REF_CLOCK_RMT_CHANNEL, 1000000, 1000000); // counter clock: 1MHz - rmt_ll_tx_enable_idle(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, true); // enable idle output - rmt_ll_tx_set_idle_level(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1); // idle level: 1 + rmt_ll_enable_periph_clock(s_rmt_hal.regs, true); + rmt_ll_set_group_clock_src(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, RMT_CLK_SRC_REFTICK, 1, 1, 0); // select REF_TICK (1MHz) + rmt_ll_tx_set_channel_clock_div(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1); // channel clock = REF_TICK / 1 = 1MHz + rmt_ll_tx_fix_idle_level(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1, true); // enable idle output, idle level: 1 rmt_ll_tx_enable_carrier_modulation(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, true); - rmt_hal_set_carrier_clock(&s_rmt_hal, REF_CLOCK_RMT_CHANNEL, 1000000, 500000, 0.5); // set carrier to 500KHz + rmt_ll_tx_set_carrier_high_low_ticks(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1, 1); // set carrier to 1MHz / (1+1) = 500KHz, 50% duty cycle rmt_ll_tx_set_carrier_level(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1); - rmt_ll_enable_mem_access(s_rmt_hal.regs, true); + rmt_ll_enable_mem_access_nonfifo(s_rmt_hal.regs, true); rmt_ll_tx_reset_pointer(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL); rmt_ll_tx_set_mem_blocks(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1); - rmt_ll_write_memory(s_rmt_hal.mem, REF_CLOCK_RMT_CHANNEL, &data, 1, 0); + RMTMEM.chan[REF_CLOCK_RMT_CHANNEL].data32[0] = data; rmt_ll_tx_enable_loop(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, false); rmt_ll_tx_start(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL);