Merge branch 'feat/support_cs_signal_in_parlio_tx' into 'master'

feat(parlio_tx): support cs signal on esp32c5 v1.0

Closes IDF-12836 and IDF-12633

See merge request espressif/esp-idf!38646
This commit is contained in:
Chen Ji Chang
2025-04-27 11:10:26 +08:00
19 changed files with 221 additions and 32 deletions

View File

@ -30,6 +30,8 @@ typedef struct {
gpio_num_t clk_out_gpio_num; /*!< GPIO number of the output clock signal, the clock is synced with TX data */ gpio_num_t clk_out_gpio_num; /*!< GPIO number of the output clock signal, the clock is synced with TX data */
gpio_num_t valid_gpio_num; /*!< GPIO number of the valid signal, which stays high when transferring data. gpio_num_t valid_gpio_num; /*!< GPIO number of the valid signal, which stays high when transferring data.
Note that, the valid signal will always occupy the MSB data bit */ Note that, the valid signal will always occupy the MSB data bit */
uint16_t valid_start_delay; /*!< The clock cycles that the valid signal becomes active before data start */
uint16_t valid_stop_delay; /*!< The clock cycles that the valid signal keeps active after data end */
size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t trans_queue_depth; /*!< Depth of internal transaction queue */
size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ size_t max_transfer_size; /*!< Maximum transfer size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */
size_t dma_burst_size; /*!< DMA burst size, in bytes */ size_t dma_burst_size; /*!< DMA burst size, in bytes */

View File

@ -130,7 +130,7 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[i], false, false); parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[i], false, false);
} }
} }
// Note: the valid signal will override TXD[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG]
if (config->valid_gpio_num >= 0) { if (config->valid_gpio_num >= 0) {
gpio_func_sel(config->valid_gpio_num, PIN_FUNC_GPIO); gpio_func_sel(config->valid_gpio_num, PIN_FUNC_GPIO);
@ -138,11 +138,20 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
if (config->flags.io_loop_back) { if (config->flags.io_loop_back) {
gpio_input_enable(config->valid_gpio_num); gpio_input_enable(config->valid_gpio_num);
} }
#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
// Configure CS signal if supported
// Note: the default value of CS signal is low, so we need to invert the CS to keep compatible with the default value
// connect the signal to the GPIO by matrix, it will also enable the output path properly // connect the signal to the GPIO by matrix, it will also enable the output path properly
esp_rom_gpio_connect_out_signal(config->valid_gpio_num,
parlio_periph_signals.groups[group_id].tx_units[unit_id].cs_sig,
!config->flags.invert_valid_out, false);
#else
// connect the signal to the GPIO by matrix, it will also enable the output path properly
// Note: the valid signal will override TXD[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG]
esp_rom_gpio_connect_out_signal(config->valid_gpio_num, esp_rom_gpio_connect_out_signal(config->valid_gpio_num,
parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG], parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG],
config->flags.invert_valid_out, false); config->flags.invert_valid_out, false);
#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
} }
if (config->clk_out_gpio_num >= 0) { if (config->clk_out_gpio_num >= 0) {
gpio_func_sel(config->clk_out_gpio_num, PIN_FUNC_GPIO); gpio_func_sel(config->clk_out_gpio_num, PIN_FUNC_GPIO);
@ -295,11 +304,16 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
// data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH // data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH
ESP_RETURN_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0), ESP_RETURN_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0),
ESP_ERR_INVALID_ARG, TAG, "invalid data width"); ESP_ERR_INVALID_ARG, TAG, "invalid data width");
// No need to check data width conflict with valid signal when CS is supported
#if PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
// data_width must not conflict with the valid signal // data_width must not conflict with the valid signal
ESP_RETURN_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG), ESP_RETURN_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG),
ESP_ERR_INVALID_ARG, TAG, "valid signal conflicts with data signal"); ESP_ERR_INVALID_ARG, TAG, "valid signal conflicts with data signal");
#endif // PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
#if SOC_PARLIO_TX_CLK_SUPPORT_GATING #if SOC_PARLIO_TX_CLK_SUPPORT_GATING
// clock gating is controlled by either the MSB bit of data bus or the valid signal // clock gating is controlled by either the MSB bit of data bus or the valid signal(or CS signal when supported)
ESP_RETURN_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE), ESP_RETURN_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE),
ESP_ERR_INVALID_ARG, TAG, "no gpio can control the clock gating"); ESP_ERR_INVALID_ARG, TAG, "no gpio can control the clock gating");
#else #else
@ -351,13 +365,25 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
// set data width // set data width
parlio_ll_tx_set_bus_width(hal->regs, data_width); parlio_ll_tx_set_bus_width(hal->regs, data_width);
unit->idle_value_mask = (1 << data_width) - 1; unit->idle_value_mask = (1 << data_width) - 1;
// set valid delay
ESP_GOTO_ON_FALSE(parlio_ll_tx_set_valid_delay(hal->regs, config->valid_start_delay, config->valid_stop_delay), ESP_ERR_INVALID_ARG, err, TAG, "invalid valid delay");
// whether to use the valid signal // whether to use the valid signal
#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
// the clock gating source is actual selectable, it doesn't rely on the available of valid GPIO.
// but there is no use case that valid signal is used, but clocking gating is still controlled by data.
if (config->valid_gpio_num >= 0) {
parlio_ll_tx_clock_gating_from_valid(hal->regs, true);
} else {
parlio_ll_tx_clock_gating_from_valid(hal->regs, false);
}
#else
if (config->valid_gpio_num >= 0) { if (config->valid_gpio_num >= 0) {
parlio_ll_tx_treat_msb_as_valid(hal->regs, true); parlio_ll_tx_treat_msb_as_valid(hal->regs, true);
unit->idle_value_mask &= ~(1 << PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG); unit->idle_value_mask &= ~(1 << PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG);
} else { } else {
parlio_ll_tx_treat_msb_as_valid(hal->regs, false); parlio_ll_tx_treat_msb_as_valid(hal->regs, false);
} }
#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
// set data byte packing order // set data byte packing order
if (data_width < 8) { if (data_width < 8) {
parlio_ll_tx_set_bit_pack_order(hal->regs, config->bit_pack_order); parlio_ll_tx_set_bit_pack_order(hal->regs, config->bit_pack_order);

View File

@ -50,8 +50,10 @@ TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]")
config.input_clk_src_freq_hz = 1000000; config.input_clk_src_freq_hz = 1000000;
config.valid_gpio_num = 0; config.valid_gpio_num = 0;
#if PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
// failed because of data line conflict with valid signal // failed because of data line conflict with valid signal
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, parlio_new_tx_unit(&config, &units[0])); TEST_ESP_ERR(ESP_ERR_INVALID_ARG, parlio_new_tx_unit(&config, &units[0]));
#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
config.data_width = 4; config.data_width = 4;
TEST_ESP_OK(parlio_new_tx_unit(&config, &units[0])); TEST_ESP_OK(parlio_new_tx_unit(&config, &units[0]));
@ -288,6 +290,73 @@ TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]")
TEST_ESP_OK(parlio_del_tx_unit(tx_unit)); TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO)); TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO));
} }
#if !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
TEST_CASE("parallel_tx_clock_gating_and_msb_coexist", "[paralio_tx]")
{
printf("init a gpio to read parlio_tx clk output\r\n");
gpio_config_t test_gpio_conf = {
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = BIT64(TEST_CLK_GPIO) | BIT64(TEST_DATA7_GPIO),
};
TEST_ESP_OK(gpio_config(&test_gpio_conf));
printf("install parlio tx unit\r\n");
parlio_tx_unit_handle_t tx_unit = NULL;
parlio_tx_unit_config_t config = {
.clk_src = PARLIO_CLK_SRC_DEFAULT,
.data_width = 8,
.clk_in_gpio_num = -1, // use internal clock source
.valid_gpio_num = TEST_VALID_GPIO, // generate the valid signal
.clk_out_gpio_num = TEST_CLK_GPIO,
.data_gpio_nums = {
TEST_DATA0_GPIO,
TEST_DATA1_GPIO,
TEST_DATA2_GPIO,
TEST_DATA3_GPIO,
TEST_DATA4_GPIO,
TEST_DATA5_GPIO,
TEST_DATA6_GPIO,
TEST_DATA7_GPIO,
},
.output_clk_freq_hz = 1 * 1000 * 1000,
.trans_queue_depth = 4,
.max_transfer_size = 256,
.bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
.sample_edge = PARLIO_SAMPLE_EDGE_POS,
.valid_start_delay = 5,
.valid_stop_delay = 5,
.flags.clk_gate_en = true, // enable clock gating, controlled by the CS signal
};
TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
printf("send packets and see if the clock is gated when there's no transaction on line\r\n");
parlio_transmit_config_t transmit_config = {
// set the idle value to 0x80, so that the MSB is high when there's no transaction
.idle_value = 0x80,
};
uint32_t size = 256;
__attribute__((aligned(64))) uint8_t payload[size];
for (int i = 0; i < size; i++) {
payload[i] = i;
}
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config));
TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));
// check if the level on the clock line is low
TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_DATA7_GPIO));
TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config));
TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));
TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
TEST_ASSERT_EQUAL(1, gpio_get_level(TEST_DATA7_GPIO));
TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
TEST_ESP_OK(gpio_reset_pin(TEST_CLK_GPIO));
}
#endif // !PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG
#endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING
#if SOC_PSRAM_DMA_CAPABLE #if SOC_PSRAM_DMA_CAPABLE

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -34,12 +34,20 @@ extern "C" {
#define TEST_LCD_PCLK_GPIO (5) #define TEST_LCD_PCLK_GPIO (5)
#define TEST_LCD_DATA0_GPIO (4) #define TEST_LCD_DATA0_GPIO (4)
#elif CONFIG_IDF_TARGET_ESP32C5 #elif CONFIG_IDF_TARGET_ESP32C5
#define TEST_LCD_BK_LIGHT_GPIO (1) #define TEST_LCD_BK_LIGHT_GPIO (5)
#define TEST_LCD_RST_GPIO (7) #define TEST_LCD_RST_GPIO (2)
#define TEST_LCD_CS_GPIO (27) #define TEST_LCD_CS_GPIO (0)
#define TEST_LCD_DC_GPIO (6) #define TEST_LCD_DC_GPIO (3)
#define TEST_LCD_PCLK_GPIO (25) #define TEST_LCD_PCLK_GPIO (1)
#define TEST_LCD_DATA0_GPIO (26) #define TEST_LCD_DATA0_GPIO (4)
#define TEST_LCD_DATA1_GPIO (9)
#define TEST_LCD_DATA2_GPIO (28)
#define TEST_LCD_DATA3_GPIO (24)
#define TEST_LCD_DATA4_GPIO (14)
#define TEST_LCD_DATA5_GPIO (23)
#define TEST_LCD_DATA6_GPIO (13)
#define TEST_LCD_DATA7_GPIO (27)
#endif #endif
#define TEST_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000) #define TEST_LCD_PIXEL_CLOCK_HZ (10 * 1000 * 1000)

View File

@ -32,11 +32,8 @@
#define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_FIFO_EMPTY | PARLIO_LL_EVENT_TX_EOF) #define PARLIO_LL_EVENT_TX_MASK (PARLIO_LL_EVENT_TX_FIFO_EMPTY | PARLIO_LL_EVENT_TX_EOF)
#define PARLIO_LL_EVENT_RX_MASK (PARLIO_LL_EVENT_RX_FIFO_FULL) #define PARLIO_LL_EVENT_RX_MASK (PARLIO_LL_EVENT_RX_FIFO_FULL)
#define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 7 // TXD[7] can be used a valid signal
#define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal #define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal
#define PARLIO_LL_TX_VALID_MAX_DELAY 32767
#define PARLIO_LL_CLK_DIVIDER_MAX (0) // Not support fractional divider
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -526,18 +523,34 @@ static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en)
} }
/** /**
* @brief Whether to treat the MSB of TXD as the valid signal * @brief Set the clock gating from the valid signal
*
* @note If enabled, TXD[7] will work as valid signal, which stay high during data transmission.
* *
* @param dev Parallel IO register base address * @param dev Parallel IO register base address
* @param en True to enable, False to disable * @param en If set to true, the clock is gated by the valid signal, otherwise it is gated by the MSB of the data line.
*/ */
static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en) static inline void parlio_ll_tx_clock_gating_from_valid(parl_io_dev_t *dev, bool en)
{ {
dev->tx_genrl_cfg.tx_valid_output_en = en; dev->tx_genrl_cfg.tx_valid_output_en = en;
} }
/**
* @brief Set TX valid signal delay
*
* @param dev Parallel IO register base address
* @param start_delay Number of clock cycles to delay
* @param stop_delay Number of clock cycles to delay
* @return true: success, false: valid delay is not supported
*/
static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay)
{
if (start_delay > PARLIO_LL_TX_VALID_MAX_DELAY || stop_delay > PARLIO_LL_TX_VALID_MAX_DELAY) {
return false;
}
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_start_delay, start_delay);
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_cs_cfg, tx_cs_stop_delay, stop_delay);
return true;
}
/** /**
* @brief Set the sample clock edge * @brief Set the sample clock edge
* *

View File

@ -509,6 +509,23 @@ static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en)
dev->tx_cfg0.tx_hw_valid_en = en; dev->tx_cfg0.tx_hw_valid_en = en;
} }
/**
* @brief Set TX valid signal delay
*
* @param dev Parallel IO register base address
* @param start_delay Number of clock cycles to delay
* @param stop_delay Number of clock cycles to delay
* @return true: success, false: valid delay is not supported
*/
static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay)
{
(void)dev;
if (start_delay == 0 && stop_delay == 0) {
return true;
}
return false;
}
/** /**
* @brief Set the sample clock edge * @brief Set the sample clock edge
* *

View File

@ -37,8 +37,6 @@
#define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 7 // TXD[7] can be used a valid signal #define PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG 7 // TXD[7] can be used a valid signal
#define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal #define PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE 7 // TXD[7] can be used as clock gate signal
#define PARLIO_LL_CLK_DIVIDER_MAX (0) // Not support fractional divider
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -534,7 +532,7 @@ static inline void parlio_ll_tx_start(parl_io_dev_t *dev, bool en)
/** /**
* @brief Whether to treat the MSB of TXD as the valid signal * @brief Whether to treat the MSB of TXD as the valid signal
* *
* @note If enabled, TXD[15] will work as valid signal, which stay high during data transmission. * @note If enabled, TXD[7] will work as valid signal, which stay high during data transmission.
* *
* @param dev Parallel IO register base address * @param dev Parallel IO register base address
* @param en True to enable, False to disable * @param en True to enable, False to disable
@ -544,6 +542,23 @@ static inline void parlio_ll_tx_treat_msb_as_valid(parl_io_dev_t *dev, bool en)
dev->tx_genrl_cfg.tx_valid_output_en = en; dev->tx_genrl_cfg.tx_valid_output_en = en;
} }
/**
* @brief Set TX valid signal delay
*
* @param dev Parallel IO register base address
* @param start_delay Number of clock cycles to delay
* @param stop_delay Number of clock cycles to delay
* @return true: success, false: valid delay is not supported
*/
static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay)
{
(void)dev;
if (start_delay == 0 && stop_delay == 0) {
return true;
}
return false;
}
/** /**
* @brief Set the sample clock edge * @brief Set the sample clock edge
* *

View File

@ -523,6 +523,23 @@ static inline void parlio_ll_tx_set_trans_bit_len(parl_io_dev_t *dev, uint32_t b
dev->tx_data_cfg.tx_bitlen = bitlen; dev->tx_data_cfg.tx_bitlen = bitlen;
} }
/**
* @brief Set TX valid signal delay
*
* @param dev Parallel IO register base address
* @param start_delay Number of clock cycles to delay
* @param stop_delay Number of clock cycles to delay
* @return true: success, false: valid delay is not supported
*/
static inline bool parlio_ll_tx_set_valid_delay(parl_io_dev_t *dev, uint32_t start_delay, uint32_t stop_delay)
{
(void)dev;
if (start_delay == 0 && stop_delay == 0) {
return true;
}
return false;
}
/** /**
* @brief Check if tx size can be determined by DMA * @brief Check if tx size can be determined by DMA
* *

View File

@ -991,6 +991,10 @@ config SOC_PARLIO_SUPPORT_SPI_LCD
bool bool
default y default y
config SOC_PARLIO_SUPPORT_I80_LCD
bool
default y
config SOC_MPI_MEM_BLOCKS_NUM config SOC_MPI_MEM_BLOCKS_NUM
int int
default 4 default 4

View File

@ -389,6 +389,7 @@
#define SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION 1 /*!< Support loop transmission */ #define SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION 1 /*!< Support loop transmission */
#define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */ #define SOC_PARLIO_SUPPORT_SLEEP_RETENTION 1 /*!< Support back up registers before sleep */
#define SOC_PARLIO_SUPPORT_SPI_LCD 1 /*!< Support to drive SPI interfaced LCD */ #define SOC_PARLIO_SUPPORT_SPI_LCD 1 /*!< Support to drive SPI interfaced LCD */
#define SOC_PARLIO_SUPPORT_I80_LCD 1 /*!< Support to drive I80 interfaced LCD */
/*--------------------------- MPI CAPS ---------------------------------------*/ /*--------------------------- MPI CAPS ---------------------------------------*/
#define SOC_MPI_MEM_BLOCKS_NUM (4) #define SOC_MPI_MEM_BLOCKS_NUM (4)

View File

@ -27,6 +27,7 @@ const parlio_signal_conn_t parlio_periph_signals = {
}, },
.clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_out_sig = PARL_TX_CLK_OUT_IDX,
.clk_in_sig = PARL_TX_CLK_IN_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX,
.cs_sig = PARL_TX_CS_O_IDX,
} }
}, },
.rx_units = { .rx_units = {

View File

@ -35,6 +35,7 @@ const parlio_signal_conn_t parlio_periph_signals = {
}, },
.clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_out_sig = PARL_TX_CLK_OUT_IDX,
.clk_in_sig = PARL_TX_CLK_IN_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX,
.cs_sig = -1,
} }
}, },
.rx_units = { .rx_units = {

View File

@ -27,6 +27,7 @@ const parlio_signal_conn_t parlio_periph_signals = {
}, },
.clk_out_sig = PARL_TX_CLK_OUT_IDX, .clk_out_sig = PARL_TX_CLK_OUT_IDX,
.clk_in_sig = PARL_TX_CLK_IN_IDX, .clk_in_sig = PARL_TX_CLK_IN_IDX,
.cs_sig = -1,
} }
}, },
.rx_units = { .rx_units = {

View File

@ -35,6 +35,7 @@ const parlio_signal_conn_t parlio_periph_signals = {
}, },
.clk_out_sig = PARLIO_TX_CLK_PAD_OUT_IDX, .clk_out_sig = PARLIO_TX_CLK_PAD_OUT_IDX,
.clk_in_sig = PARLIO_TX_CLK_PAD_IN_IDX, .clk_in_sig = PARLIO_TX_CLK_PAD_IN_IDX,
.cs_sig = -1,
} }
}, },
.rx_units = { .rx_units = {

View File

@ -29,6 +29,7 @@ typedef struct {
const int data_sigs[SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH]; const int data_sigs[SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH];
const int clk_out_sig; const int clk_out_sig;
const int clk_in_sig; const int clk_in_sig;
const int cs_sig;
} tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; } tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP];
struct { struct {
const int data_sigs[SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH]; const int data_sigs[SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH];

View File

@ -68,7 +68,9 @@ The following are the configuration parameters of the :cpp:type:`parlio_tx_unit_
- :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` The GPIO number for the output clock signal. - :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` The GPIO number for the output clock signal.
- :cpp:member:`parlio_tx_unit_config_t::data_width` The data bus width of the TX unit, must be a power of 2 and not greater than {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}. - :cpp:member:`parlio_tx_unit_config_t::data_width` The data bus width of the TX unit, must be a power of 2 and not greater than {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}.
- :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` The GPIO numbers for TX data, unused GPIOs should be set to -1. - :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` The GPIO numbers for TX data, unused GPIOs should be set to -1.
- :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` The GPIO number for the valid signal, set to -1 if not used. The valid signal stays high level when the TX unit is transmitting data. Note that enabling the valid signal will occupy the MSB data bit, reducing the maximum data width of the TX unit by 1 bit. In this case, the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` The GPIO number for the valid signal, set to -1 if not used. The valid signal stays high level when the TX unit is transmitting data. Note that enabling the valid signal in some specific chips will occupy the MSB data bit, reducing the maximum data width of the TX unit by 1 bit. In this case, the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. Please check the return value of :cpp:func:`parlio_new_tx_unit`.
- :cpp:member:`parlio_tx_unit_config_t::valid_start_delay` The number of clock cycles the valid signal will stay high level before the TX unit starts transmitting data. This configuration option depends on specific hardware features, and if enabled on unsupported chips or configured with invalid values, you will see an error message like ``invalid valid delay``.
- :cpp:member:`parlio_tx_unit_config_t::valid_stop_delay` The number of clock cycles the valid signal will stay high level after the TX unit finishes transmitting data. This configuration option depends on specific hardware features, and if enabled on unsupported chips or configured with invalid values, you will see an error message like ``invalid valid delay``.
- :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` The depth of the internal transaction queue. The deeper the queue, the more transactions can be prepared in the pending queue. - :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` The depth of the internal transaction queue. The deeper the queue, the more transactions can be prepared in the pending queue.
- :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` The maximum transfer size per transaction (in bytes). - :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` The maximum transfer size per transaction (in bytes).
- :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` The DMA burst transfer size (in bytes), must be a power of 2. - :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` The DMA burst transfer size (in bytes), must be a power of 2.
@ -76,7 +78,7 @@ The following are the configuration parameters of the :cpp:type:`parlio_tx_unit_
- :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` Sets the order of data bits within a byte (valid only when data width < 8). - :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` Sets the order of data bits within a byte (valid only when data width < 8).
- :cpp:member:`parlio_tx_unit_config_t::flags` Usually used to fine-tune some behaviors of the driver, including the following options - :cpp:member:`parlio_tx_unit_config_t::flags` Usually used to fine-tune some behaviors of the driver, including the following options
- :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` Determines whether to invert the valid signal before sending it to the GPIO pin. - :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` Determines whether to invert the valid signal before sending it to the GPIO pin.
:SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` Enables TX unit clock gating, the output clock will be controlled by the MSB bit of the data bus, i.e., by writing a high level to :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] to enable clock output, and a low level to disable it. Note that if both the valid signal output and clock gating are enabled, clock gating can come from the valid signal occupying the MSB data bit, in which case the data bus width can be as long as it is not greater than :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2. Otherwise, the data bus width needs to be configured as :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`. :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` Enables TX unit clock gating, the output clock will be controlled by the MSB bit of the data bus, i.e., by writing a high level to :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] to enable clock output, and a low level to disable it. In this case, the data bus width needs to be configured as :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`. Note that if both the valid signal output and clock gating are enabled, clock gating can come from the valid signal. there is no limit on the data bus width. (Note that in some chips, the valid signal occupies the MSB data bit, so the maximum configurable data bus width is :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2)
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` Configures whether the driver allows the system to turn off the peripheral power in sleep mode. Before entering sleep, the system will back up the TX unit register context, and these contexts will be restored when the system exits sleep mode. Turning off the peripheral can save more power, but at the cost of consuming more memory to save the register context. You need to balance power consumption and memory usage. This configuration option depends on specific hardware features, and if enabled on unsupported chips, you will see an error message like ``register back up is not supported``. :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` Configures whether the driver allows the system to turn off the peripheral power in sleep mode. Before entering sleep, the system will back up the TX unit register context, and these contexts will be restored when the system exits sleep mode. Turning off the peripheral can save more power, but at the cost of consuming more memory to save the register context. You need to balance power consumption and memory usage. This configuration option depends on specific hardware features, and if enabled on unsupported chips, you will see an error message like ``register back up is not supported``.
.. note:: .. note::

View File

@ -68,7 +68,9 @@
- :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` 输出时钟信号的 GPIO 编号。 - :cpp:member:`parlio_tx_unit_config_t::clk_out_gpio_num` 输出时钟信号的 GPIO 编号。
- :cpp:member:`parlio_tx_unit_config_t::data_width` TX 单元数据总线宽度,必须为 2 的幂次方,且不能大于 {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}。 - :cpp:member:`parlio_tx_unit_config_t::data_width` TX 单元数据总线宽度,必须为 2 的幂次方,且不能大于 {IDF_TARGET_SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH}。
- :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` TX 数据 GPIO 编号,未使用的 GPIO 设置为 -1。 - :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` TX 数据 GPIO 编号,未使用的 GPIO 设置为 -1。
- :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` 有效信号的 GPIO 编号,未使用则设置为 -1。有效信号会在 TX 传输数据时保持高电平。注意,启用有效信号会占用 MSB 数据位,导致 TX 单元的最大数据宽度减少 1 位,此时数据总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2。 - :cpp:member:`parlio_tx_unit_config_t::valid_gpio_num` 有效信号的 GPIO 编号,未使用则设置为 -1。有效信号会在 TX 传输数据时保持高电平。注意,在部分芯片上启用有效信号会占用 MSB 数据位,导致 TX 单元的最大数据宽度减少 1 位,此时数据总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2 因此请检查 :cpp:func:`parlio_new_tx_unit` 的返回值
- :cpp:member:`parlio_tx_unit_config_t::valid_start_delay` 有效信号将在数据发送之前保持“有效”状态的时钟周期。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,或配置了无效的值,你将看到类似 ``invalid valid delay`` 的错误消息。
- :cpp:member:`parlio_tx_unit_config_t::valid_stop_delay` 有效信号将在数据发送完成之后保持“有效”状态的时钟周期。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,或配置了无效的值,你将看到类似 ``invalid valid delay`` 的错误消息。
- :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` 内部事务队列深度。队列越深,在待处理队列中可以准备的事务越多。 - :cpp:member:`parlio_tx_unit_config_t::trans_queue_depth` 内部事务队列深度。队列越深,在待处理队列中可以准备的事务越多。
- :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` 一次传输的最大传输大小(以字节为单位)。 - :cpp:member:`parlio_tx_unit_config_t::max_transfer_size` 一次传输的最大传输大小(以字节为单位)。
- :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` DMA 突发传输大小(以字节为单位),必须为 2 的幂次方。 - :cpp:member:`parlio_tx_unit_config_t::dma_burst_size` DMA 突发传输大小(以字节为单位),必须为 2 的幂次方。
@ -76,7 +78,7 @@
- :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` 设置字节内数据位出现的顺序(仅当数据宽度 < 8 时有效)。 - :cpp:member:`parlio_tx_unit_config_t::bit_pack_order` 设置字节内数据位出现的顺序(仅当数据宽度 < 8 时有效)。
- :cpp:member:`parlio_tx_unit_config_t::flags` 通常用来微调驱动的一些行为,包括以下选项 - :cpp:member:`parlio_tx_unit_config_t::flags` 通常用来微调驱动的一些行为,包括以下选项
- :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` 决定是否在将 TX 单元有效信号发送到 GPIO 管脚前反转信号。 - :cpp:member:`parlio_tx_unit_config_t::flags::invert_valid_out` 决定是否在将 TX 单元有效信号发送到 GPIO 管脚前反转信号。
:SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` 启用 TX 单元时钟门控,输出时钟由数据总线的 MSB 位控制,即通过向 :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] 写入高电平使能时钟输出,低电平禁用。注意,若有效信号输出和时钟门控同时启用,时钟门控可以来自占用 MSB 数据位的有效信号,此时数据总线宽只要不大于:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2 即可,否则需要配置数据总线宽度为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`。 :SOC_PARLIO_TX_CLK_SUPPORT_GATING: - :cpp:member:`parlio_tx_unit_config_t::flags::clk_gate_en` 启用 TX 单元时钟门控,输出时钟默认由数据总线的 MSB 位控制,即通过向 :cpp:member:`parlio_tx_unit_config_t::data_gpio_nums` [:c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` - 1] 写入高电平使能时钟输出,低电平禁用,此时需要配置数据总线宽度为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH`。注意,若有效信号输出和时钟门控同时启用,时钟门控则来自有效信号,对数据总线宽度没有额外要求(部分芯片上有效信号会占用 MSB 数据位,总线宽度的最大可配置为 :c:macro:`SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH` / 2
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` 配置驱动程序是否允许系统在睡眠模式下关闭外设电源。在进入睡眠之前,系统将备份 TX 单元寄存器上下文,当系统退出睡眠模式时,这些上下文将被恢复。关闭外设可以节省更多功耗,但代价是消耗更多内存来保存寄存器上下文。你需要在功耗和内存消耗之间做权衡。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,你将看到类似 ``register back up is not supported`` 的错误消息。 :SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - :cpp:member:`parlio_tx_unit_config_t::flags::allow_pd` 配置驱动程序是否允许系统在睡眠模式下关闭外设电源。在进入睡眠之前,系统将备份 TX 单元寄存器上下文,当系统退出睡眠模式时,这些上下文将被恢复。关闭外设可以节省更多功耗,但代价是消耗更多内存来保存寄存器上下文。你需要在功耗和内存消耗之间做权衡。此配置选项依赖于特定的硬件功能,如果在不支持的芯片上启用它,你将看到类似 ``register back up is not supported`` 的错误消息。
.. note:: .. note::

View File

@ -9,6 +9,7 @@ menu "Example Configuration"
choice EXAMPLE_LCD_PARLIO_SIMULATE_INTERFACE choice EXAMPLE_LCD_PARLIO_SIMULATE_INTERFACE
prompt "LCD interface" prompt "LCD interface"
default EXAMPLE_LCD_PARLIO_SIMULATE_I80 if SOC_PARLIO_SUPPORT_I80_LCD
default EXAMPLE_LCD_PARLIO_SIMULATE_SPI default EXAMPLE_LCD_PARLIO_SIMULATE_SPI
help help
Select LCD controller model Select LCD controller model

View File

@ -4,9 +4,16 @@ CONFIG_SPIRAM_SPEED_80M=y
# the Frame Buffer is allocated from the PSRAM and fetched by EDMA # the Frame Buffer is allocated from the PSRAM and fetched by EDMA
CONFIG_SPIRAM_XIP_FROM_PSRAM=y CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_EXAMPLE_PIN_NUM_BK_LIGHT=1 CONFIG_EXAMPLE_PIN_NUM_BK_LIGHT=5
CONFIG_EXAMPLE_PIN_NUM_RST=7 CONFIG_EXAMPLE_PIN_NUM_RST=2
CONFIG_EXAMPLE_PIN_NUM_PCLK=25 CONFIG_EXAMPLE_PIN_NUM_PCLK=1
CONFIG_EXAMPLE_PIN_NUM_CS=27 CONFIG_EXAMPLE_PIN_NUM_CS=0
CONFIG_EXAMPLE_PIN_NUM_DC=6 CONFIG_EXAMPLE_PIN_NUM_DC=3
CONFIG_EXAMPLE_PIN_NUM_DATA0=26 CONFIG_EXAMPLE_PIN_NUM_DATA0=4
CONFIG_EXAMPLE_PIN_NUM_DATA1=9
CONFIG_EXAMPLE_PIN_NUM_DATA2=28
CONFIG_EXAMPLE_PIN_NUM_DATA3=24
CONFIG_EXAMPLE_PIN_NUM_DATA4=14
CONFIG_EXAMPLE_PIN_NUM_DATA5=23
CONFIG_EXAMPLE_PIN_NUM_DATA6=13
CONFIG_EXAMPLE_PIN_NUM_DATA7=27