Merge branch 'feature/rmt_hal_dma' into 'master'

rmt: document and improve LL driver

See merge request espressif/esp-idf!17297
This commit is contained in:
morris 2022-03-09 17:55:08 +08:00
commit da28f7e2d9
38 changed files with 3411 additions and 2124 deletions

View File

@ -6,10 +6,6 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#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, /*<! RMT memory access in FIFO mode */
RMT_DATA_MODE_MEM, /*<! RMT memory access in memory mode */
RMT_DATA_MODE_MAX,
} rmt_data_mode_t;
/**
* @brief RMT Channel Working Mode (TX or RX)
*
*/
typedef enum {
RMT_MODE_TX, /*!< RMT TX mode */
RMT_MODE_RX, /*!< RMT RX mode */
RMT_MODE_MAX
} rmt_mode_t;
/**
* @brief RMT Idle Level
*
*/
typedef enum {
RMT_IDLE_LEVEL_LOW, /*!< RMT TX idle level: low Level */
RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */
RMT_IDLE_LEVEL_MAX,
} rmt_idle_level_t;
/**
* @brief RMT Carrier Level
*
*/
typedef enum {
RMT_CARRIER_LEVEL_LOW, /*!< RMT carrier wave is modulated for low Level output */
RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */
RMT_CARRIER_LEVEL_MAX
} rmt_carrier_level_t;
/**
* @brief RMT Channel Status
*
*/
typedef enum {
RMT_CHANNEL_UNINIT, /*!< RMT channel uninitialized */
RMT_CHANNEL_IDLE, /*!< RMT channel status idle */
RMT_CHANNEL_BUSY, /*!< RMT channel status busy */
} rmt_channel_status_t;
/**
* @brief Data struct of RMT channel status
*/
typedef struct {
rmt_channel_status_t status[RMT_CHANNEL_MAX]; /*!< Store the current status of each channel */
} rmt_channel_status_result_t;
/**
* @brief Data struct of RMT TX configure parameters
*/
@ -888,7 +999,7 @@ esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count);
* - When the loop auto-stop feature is enabled will halt RMT transmission after the loop count reaches a certain threshold
* - When disabled, the RMT transmission continue indefinitely until halted by the users
*
* @note The auto-stop feature is implemented in hardware on particular targets (i.e. those with SOC_RMT_SUPPORT_TX_LOOP_AUTOSTOP defined).
* @note The auto-stop feature is implemented in hardware on particular targets (i.e. those with SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP defined).
* Otherwise, the auto-stop feature is implemented in software via the interrupt.
*
* @param channel RMT channel
@ -900,50 +1011,6 @@ esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count);
esp_err_t rmt_enable_tx_loop_autostop(rmt_channel_t channel, bool en);
#endif // SOC_RMT_SUPPORT_TX_LOOP_COUNT
/**
* @brief Reset RMT TX/RX memory index.
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)
__attribute__((deprecated("use rmt_tx_memory_reset or rmt_rx_memory_reset instead")));
/**
* @brief Set mask value to RMT interrupt enable register.
*
* @param mask Bit mask to set to the register
*
*/
void rmt_set_intr_enable_mask(uint32_t mask)
__attribute__((deprecated("interrupt should be handled by driver")));
/**
* @brief Clear mask value to RMT interrupt enable register.
*
* @param mask Bit mask to clear the register
*
*/
void rmt_clr_intr_enable_mask(uint32_t mask)
__attribute__((deprecated("interrupt should be handled by driver")));
/**
* @brief Set RMT pin
*
* @param channel RMT channel
* @param mode TX or RX mode for RMT
* @param gpio_num GPIO number to transmit or receive the signal.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num)
__attribute__((deprecated("use rmt_set_gpio instead")));
#ifdef __cplusplus
}
#endif

View File

@ -20,6 +20,7 @@
#include "freertos/ringbuf.h"
#include "soc/soc_memory_layout.h"
#include "soc/rmt_periph.h"
#include "soc/rmt_struct.h"
#include "soc/rtc.h"
#include "hal/rmt_hal.h"
#include "hal/rmt_ll.h"
@ -97,8 +98,7 @@ typedef struct {
} rmt_obj_t;
static rmt_contex_t rmt_contex = {
.hal.regs = RMT_LL_HW_BASE,
.hal.mem = RMT_LL_MEM_BASE,
.hal.regs = &RMT,
.rmt_spinlock = portMUX_INITIALIZER_UNLOCKED,
.rmt_driver_intr_handle = NULL,
.rmt_tx_end_callback = {
@ -117,6 +117,9 @@ static uint32_t s_rmt_source_clock_hz[RMT_CHANNEL_MAX];
static uint32_t s_rmt_source_clock_hz;
#endif
// RMTMEM address is declared in <target>.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();

View File

@ -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);

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <stddef.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[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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdint.h>
#include <stdbool.h>
#include <stddef.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[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

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
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

View File

@ -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, /*<! RMT memory access in FIFO mode */
RMT_DATA_MODE_MEM, /*<! RMT memory access in memory mode */
RMT_DATA_MODE_MAX,
} rmt_data_mode_t;
/**
* @brief RMT Channel Working Mode (TX or RX)
*
*/
typedef enum {
RMT_MODE_TX, /*!< RMT TX mode */
RMT_MODE_RX, /*!< RMT RX mode */
RMT_MODE_MAX
} rmt_mode_t;
/**
* @brief RMT Idle Level
*
*/
typedef enum {
RMT_IDLE_LEVEL_LOW, /*!< RMT TX idle level: low Level */
RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */
RMT_IDLE_LEVEL_MAX,
} rmt_idle_level_t;
/**
* @brief RMT Carrier Level
*
*/
typedef enum {
RMT_CARRIER_LEVEL_LOW, /*!< RMT carrier wave is modulated for low Level output */
RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */
RMT_CARRIER_LEVEL_MAX
} rmt_carrier_level_t;
/**
* @brief RMT Channel Status
*
*/
typedef enum {
RMT_CHANNEL_UNINIT, /*!< RMT channel uninitialized */
RMT_CHANNEL_IDLE, /*!< RMT channel status idle */
RMT_CHANNEL_BUSY, /*!< RMT channel status busy */
} rmt_channel_status_t;
/**
* @brief Data struct of RMT channel status
*/
typedef struct {
rmt_channel_status_t status[RMT_CHANNEL_MAX]; /*!< Store the current status of each channel */
} rmt_channel_status_result_t;
typedef union {
struct {
unsigned int duration0 : 15; /*!< Duration of level0 */
unsigned int level0 : 1; /*!< Level of the first part */
unsigned int duration1 : 15; /*!< Duration of level1 */
unsigned int level1 : 1; /*!< Level of the second part */
};
unsigned int val; /*!< Equivelent unsigned value for the RMT symbol */
} rmt_symbol_word_t;
#ifdef __cplusplus
}

View File

@ -10,53 +10,23 @@
void rmt_hal_init(rmt_hal_context_t *hal)
{
hal->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));
}

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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_ */

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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_ */

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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 <stdint.h>
#include "soc/soc.h"
#include "soc.h"
#ifdef __cplusplus
extern "C" {

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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 <stdint.h>
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -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
*/

View File

@ -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 */

View File

@ -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"

View File

@ -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

View File

@ -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 \

View File

@ -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
^^^^^^^^^^^^^^^

View File

@ -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

View File

@ -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.

View File

@ -968,7 +968,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
@ -1323,7 +1322,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
@ -1356,7 +1354,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
@ -1394,7 +1391,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
@ -1424,7 +1420,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
@ -1472,7 +1467,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
@ -1556,7 +1550,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
@ -1606,7 +1599,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
@ -1656,7 +1648,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
@ -1675,7 +1666,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

View File

@ -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 <target>.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);