change(ulp): bu lp i2c on esp32c5

This commit is contained in:
Xiaoyu Liu 2024-07-11 11:28:40 +08:00
parent fad3d5aae0
commit 1216dd1abd
10 changed files with 147 additions and 28 deletions

View File

@ -19,6 +19,8 @@
#include "soc/pcr_struct.h"
#include "hal/i2c_types.h"
#include "soc/clk_tree_defs.h"
#include "soc/lp_clkrst_struct.h"
#include "soc/lpperi_struct.h"
#include "hal/misc.h"
#ifdef __cplusplus
@ -69,7 +71,7 @@ typedef enum {
} i2c_ll_slave_intr_t;
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (&I2C0)
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == I2C_NUM_0) ? (&I2C0) : (&LP_I2C))
#define I2C_LL_MASTER_EVENT_INTR (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
#define I2C_LL_SLAVE_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M|I2C_TXFIFO_WM_INT_ENA_M|I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
#define I2C_LL_SLAVE_RX_EVENT_INTR (I2C_TRANS_COMPLETE_INT_ENA_M | I2C_RXFIFO_WM_INT_ENA_M | I2C_SLAVE_STRETCH_INT_ENA_M)
@ -77,6 +79,14 @@ typedef enum {
#define I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT (9)
#define I2C_LL_SCL_WAIT_US_VAL_DEFAULT (2500) // Approximate value for SCL timeout regs (in us).
// Record for Pins usage logs
#define LP_I2C_SCL_PIN_ERR_LOG "SCL pin can only be configured as GPIO#7"
#define LP_I2C_SDA_PIN_ERR_LOG "SDA pin can only be configured as GPIO#6"
#define LP_I2C_SDA_IOMUX_PAD 6
#define LP_I2C_SCL_IOMUX_PAD 7
/**
* @brief Calculate I2C bus frequency
* Note that the clock accuracy is affected by the external pull-up resistor,
@ -752,6 +762,20 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses)
hw->ctr.conf_upgate = 1;
}
/**
* @brief Set the ACK level that the I2C master must send when the Rx FIFO count has reached the threshold value.
* ack_level: 1 (NACK)
* ack_level: 0 (ACK)
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_rx_full_ack_level(i2c_dev_t *hw, int ack_level)
{
hw->ctr.rx_full_ack_level = ack_level;
}
/**
* @brief Set I2C source clock
*
@ -762,10 +786,73 @@ static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw, uint32_t slave_pulses)
*/
static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_clk)
{
if (hw == &LP_I2C) {
// Do nothing
return;
}
// src_clk : (1) for RTC_CLK, (0) for XTAL
PCR.i2c[0].i2c_sclk_conf.i2c_sclk_sel = (src_clk == I2C_CLK_SRC_RC_FAST) ? 1 : 0;
}
/**
* @brief Set LP I2C source clock
*
* @param hw Address offset of the LP I2C peripheral registers
* @param src_clk Source clock for the LP I2C peripheral
*
* @return None
*/
static inline void lp_i2c_ll_set_source_clk(i2c_dev_t *hw, soc_periph_lp_i2c_clk_src_t src_clk)
{
(void)hw;
// src_clk : (0) for LP_FAST_CLK (RTC Fast), (1) for XTAL_D2_CLK
switch (src_clk) {
case LP_I2C_SCLK_LP_FAST:
LP_CLKRST.lpperi.lp_i2c_clk_sel = 0;
break;
case LP_I2C_SCLK_XTAL_D2:
LP_CLKRST.lpperi.lp_i2c_clk_sel = 1;
break;
default:
// Invalid source clock selected
abort();
}
}
/// LP_CLKRST.lpperi is a shared register, so this function must be used in an atomic way
#define lp_i2c_ll_set_source_clk(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_i2c_ll_set_source_clk(__VA_ARGS__)
/**
* @brief Enable bus clock for the LP I2C module
*
* @param hw_id LP I2C instance ID
* @param enable True to enable, False to disable
*/
static inline void _lp_i2c_ll_enable_bus_clock(int hw_id, bool enable)
{
(void)hw_id;
LPPERI.clk_en.lp_ext_i2c_ck_en = enable;
}
/// LPPERI.clk_en is a shared register, so this function must be used in an atomic way
#define lp_i2c_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _lp_i2c_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset LP I2C module
*
* @param hw_id LP I2C instance ID
*/
static inline void lp_i2c_ll_reset_register(int hw_id)
{
(void)hw_id;
LPPERI.reset_en.lp_ext_i2c_reset_en = 1;
LPPERI.reset_en.lp_ext_i2c_reset_en = 0;
}
/// LPPERI.reset_en is a shared register, so this function must be used in an atomic way
#define lp_i2c_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_i2c_ll_reset_register(__VA_ARGS__)
/**
* @brief Enable I2C peripheral controller clock
*
@ -774,7 +861,11 @@ static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_clock_source_t src_c
*/
static inline void i2c_ll_enable_controller_clock(i2c_dev_t *hw, bool en)
{
(void)hw;
if (hw == &LP_I2C) {
// Do nothing
return;
}
PCR.i2c[0].i2c_sclk_conf.i2c_sclk_en = en;
}

View File

@ -10,13 +10,35 @@
/*
Bunch of constants for every I2C peripheral: GPIO signals, irqs, hw addr of registers etc
*/
typedef enum
{
LP_I2C_MUX_FUNC = 0,
LP_GPIO_MUX_FUNC = 1,
LP_IO_MUX_FUNC_NUM = 2,
LP_MUX_FUNC_NOT_USED = 0xFF,
} lp_io_mux_func_t;
static_assert(SOC_I2C_NUM == (SOC_HP_I2C_NUM + SOC_LP_I2C_NUM));
const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM] = {
/* I2C_NUM_0*/
{
.sda_out_sig = I2CEXT0_SDA_OUT_IDX,
.sda_in_sig = I2CEXT0_SDA_IN_IDX,
.scl_out_sig = I2CEXT0_SCL_OUT_IDX,
.scl_in_sig = I2CEXT0_SCL_IN_IDX,
.iomux_func = (uint8_t)LP_MUX_FUNC_NOT_USED,
.irq = ETS_I2C_EXT0_INTR_SOURCE,
.module = PERIPH_I2C0_MODULE,
},
/* LP_I2C_NUM_0*/
{
.sda_out_sig = 0,
.sda_in_sig = 0,
.scl_out_sig = 0,
.scl_in_sig = 0,
.iomux_func = (uint8_t)LP_I2C_MUX_FUNC,
.irq = ETS_LP_I2C_INTR_SOURCE,
.module = PERIPH_LP_I2C0_MODULE,
},
};

View File

@ -167,6 +167,10 @@ config SOC_LP_PERIPHERALS_SUPPORTED
bool
default y
config SOC_LP_I2C_SUPPORTED
bool
default y
config SOC_ULP_LP_UART_SUPPORTED
bool
default y
@ -505,7 +509,7 @@ config SOC_DEDIC_PERIPH_ALWAYS_ENABLE
config SOC_I2C_NUM
int
default 1
default 2
config SOC_HP_I2C_NUM
int
@ -555,6 +559,14 @@ config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH
bool
default y
config SOC_LP_I2C_NUM
int
default 1
config SOC_LP_I2C_FIFO_LEN
int
default 16
config SOC_I2S_NUM
int
default 1

View File

@ -347,15 +347,15 @@ typedef enum { // TODO: [ESP32C5] IDF-8694, IDF-8696 (inherit from C6)
/**
* @brief Array initializer for all supported clock sources of LP_I2C
*/
#define SOC_LP_I2C_CLKS {SOC_MOD_CLK_RTC_FAST, SOC_MOD_CLK_XTAL_D2}
#define SOC_LP_I2C_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_D2}
/**
* @brief Type of LP_I2C clock source.
*/
typedef enum { // TODO: [ESP32C5] IDF-8695 (inherit from C6)
LP_I2C_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock is RTC_FAST */
LP_I2C_SCLK_LP_FAST = SOC_MOD_CLK_RC_FAST, /*!< LP_I2C source clock is RC_FAST */
LP_I2C_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_I2C source clock is XTAL_D2 */
LP_I2C_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_I2C source clock default choice is RTC_FAST */
LP_I2C_SCLK_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< LP_I2C source clock default choice is RC_FAST */
} soc_periph_lp_i2c_clk_src_t;
/////////////////////////////////////////////////SPI////////////////////////////////////////////////////////////////////

View File

@ -1103,6 +1103,7 @@ typedef struct {
} i2c_dev_t;
extern i2c_dev_t I2C0;
extern i2c_dev_t LP_I2C;
#ifndef __cplusplus
_Static_assert(sizeof(i2c_dev_t) == 0x200, "Invalid size of i2c_dev_t structure");

View File

@ -63,7 +63,7 @@
#define SOC_LP_TIMER_SUPPORTED 1
// #define SOC_LP_AON_SUPPORTED 1 // TODO: [ESP32C5] IDF-8638
#define SOC_LP_PERIPHERALS_SUPPORTED 1
// #define SOC_LP_I2C_SUPPORTED 1 // TODO: [ESP32C5] IDF-8634
#define SOC_LP_I2C_SUPPORTED 1
#define SOC_ULP_LP_UART_SUPPORTED 1
#define SOC_CLK_TREE_SUPPORTED 1
// #define SOC_ASSIST_DEBUG_SUPPORTED 1 // TODO: [ESP32C5] IDF-8663
@ -242,8 +242,7 @@
#define SOC_DEDIC_PERIPH_ALWAYS_ENABLE (1) /*!< The dedicated GPIO (a.k.a. fast GPIO) is featured by some customized CPU instructions, which is always enabled */
/*-------------------------- I2C CAPS ----------------------------------------*/
// ESP32-C5 has 1 I2C
#define SOC_I2C_NUM (1U)
#define SOC_I2C_NUM (2U)
#define SOC_HP_I2C_NUM (1U)
#define SOC_I2C_FIFO_LEN (32) /*!< I2C hardware FIFO depth */
@ -263,9 +262,9 @@
/*-------------------------- LP_I2C CAPS -------------------------------------*/
// ESP32-C5 has 1 LP_I2C
// #define SOC_LP_I2C_NUM (1U)
#define SOC_LP_I2C_NUM (1U)
// #define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */
#define SOC_LP_I2C_FIFO_LEN (16) /*!< LP_I2C hardware FIFO depth */
/*-------------------------- I2S CAPS ----------------------------------------*/
#define SOC_I2S_NUM (1U)

View File

@ -881,7 +881,7 @@ typedef struct lp_i2c_dev_t {
volatile lp_i2c_rxfifo_start_addr_reg_t rxfifo_start_addr;
} lp_i2c_dev_t;
// We map the LP_I2C instance to the i2c_dev_t struct for convinience of using the same HAL/LL. See soc/i2c_struct.h
// We map the LP_I2C instance to the i2c_dev_t struct for convenience of using the same HAL/LL. See soc/i2c_struct.h
//extern lp_i2c_dev_t LP_I2C;
#ifndef __cplusplus

View File

@ -14,12 +14,7 @@
static const char *LPI2C_TAG = "lp_core_i2c";
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
#include "soc/lp_io_struct.h"
/* Use the register structure to access LP_IO module registers */
lp_io_dev_t *lp_io_dev = &LP_IO;
#else
#if SOC_LP_GPIO_MATRIX_SUPPORTED
#include "driver/lp_io.h"
#include "soc/lp_gpio_sig_map.h"
#endif /* !SOC_LP_GPIO_MATRIX_SUPPORTED */
@ -94,11 +89,9 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg)
ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA pin config failed");
#if !SOC_LP_GPIO_MATRIX_SUPPORTED
/* Select LP I2C function for the SDA Pin */
lp_io_dev->gpio[sda_io_num].mcu_sel = 1;
/* Select LP I2C function for the SCL Pin */
lp_io_dev->gpio[scl_io_num].mcu_sel = 1;
const i2c_signal_conn_t *p_i2c_pin = &i2c_periph_signal[LP_I2C_NUM_0];
ret = rtc_gpio_iomux_func_sel(sda_io_num, p_i2c_pin->iomux_func);
ret = rtc_gpio_iomux_func_sel(scl_io_num, p_i2c_pin->iomux_func);
#else
/* Connect the SDA pin of the LP_I2C peripheral to the LP_IO Matrix */
ret = lp_gpio_connect_out_signal(sda_io_num, LP_I2C_SDA_PAD_OUT_IDX, 0, 0);

View File

@ -301,7 +301,7 @@ examples/system/ulp/lp_core/interrupt:
examples/system/ulp/lp_core/lp_i2c:
enable:
- if: SOC_LP_I2C_SUPPORTED == 1
- if: SOC_LP_I2C_SUPPORTED == 1 and SOC_DEEP_SLEEP_SUPPORTED == 1
disable:
- if: IDF_TARGET == "esp32p4"
temporary: true

View File

@ -7,13 +7,13 @@
## Overview
This example demonstrates basic usage of the LP I2C driver from the LP core by reading to and writing from a sensor connected over I2C.
This example demonstrates the basic usage of the LP I2C driver from the LP core by reading to and writing from a sensor connected over I2C.
## How to use example
### Hardware Required
To run this example, you should have a ESP32-C6 based development board as well as a BH1750 sensor. BH1750 is an ambient light sensor. More information about it can be found in the [BH1750 datasheet](https://www.mouser.com/datasheet/2/348/bh1750fvi-e-186247.pdf).
To run this example, you should have an ESP based development board that supports the LP I2C peripheral on the LP Core as well as a BH1750 sensor. BH1750 is an ambient light sensor. More information about it can be found in the [BH1750 datasheet](https://www.mouser.com/datasheet/2/348/bh1750fvi-e-186247.pdf).
#### Pin Assignment:
@ -22,9 +22,10 @@ To run this example, you should have a ESP32-C6 based development board as well
| | SDA | SCL |
| ----------------------- | ------| ------|
| ESP32-C6 LP I2C Master | GPIO6 | GPIO7 |
| ESP32-C5 LP I2C Master | GPIO6 | GPIO7 |
| BH1750 Sensor | SDA | SCL |
**Note:** There's no need to add an external pull-up resistors for SDA/SCL pin, because the driver enables the internal pull-up resistors.
**Note:** There's no need to add external pull-up resistors for SDA/SCL pin, because the driver enables the internal pull-up resistors.
### Build and Flash
@ -51,7 +52,7 @@ LP core woke up the main CPU
Lux = 3
Entering deep sleep...
(When the BH1750 sensor is exposed to a direct light source, the Lux value should be larger and the LP core should wakup the main CPU)
(When the BH1750 sensor is exposed to a direct light source, the Lux value should be larger and the LP core should wakeup the main CPU)
LP core woke up the main CPU
Lux = 1222