Prvni ulozeni z chegewara githubu

This commit is contained in:
2023-02-25 16:13:53 +01:00
commit 01eb80dfe2
3279 changed files with 638407 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* 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
******************************************************************************/
// The HAL layer for ADC (esp32 specific part)
#pragma once
#include "hal/adc_ll.h"
#include "hal/adc_types.h"
#include_next "hal/adc_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Hall sensor setting
---------------------------------------------------------------*/
/**
* Start hall convert and return the hall value.
*
* @return Hall value.
*/
int adc_hal_hall_convert(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,31 @@
// 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.
#pragma once
#define SOC_ADC1_DATA_INVERT_DEFAULT (1)
#define SOC_ADC2_DATA_INVERT_DEFAULT (1)
#define SOC_ADC_DIGI_DATA_INVERT_DEFAULT(PERIPH_NUM) (1)
#define SOC_ADC_FSM_RSTB_WAIT_DEFAULT (8)
#define SOC_ADC_FSM_START_WAIT_DEFAULT (SOC_ADC_DIGI_SAR_CLK_DIV_DEFAULT)
#define SOC_ADC_FSM_STANDBY_WAIT_DEFAULT (100)
#define ADC_FSM_SAMPLE_CYCLE_DEFAULT (2)
#define SOC_ADC_PWDET_CCT_DEFAULT (4)
#define SOC_ADC_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (2)
#define SOC_ADC_DIGI_SAR_CLK_DIV_DEFAULT (16)

View File

@@ -0,0 +1,703 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/adc_periph.h"
#include "hal/adc_types.h"
#include "soc/rtc_io_struct.h"
#include "soc/sens_struct.h"
#include "soc/syscon_struct.h"
#include "soc/rtc_cntl_struct.h"
#include <stdbool.h>
#include "hal/misc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ADC_NUM_1 = 0, /*!< SAR ADC 1 */
ADC_NUM_2 = 1, /*!< SAR ADC 2 */
ADC_NUM_MAX,
} adc_ll_num_t;
typedef enum {
ADC_POWER_BY_FSM, /*!< ADC XPD controlled by FSM. Used for polling mode */
ADC_POWER_SW_ON, /*!< ADC XPD controlled by SW. power on. Used for DMA mode */
ADC_POWER_SW_OFF, /*!< ADC XPD controlled by SW. power off. */
ADC_POWER_MAX, /*!< For parameter check. */
} adc_ll_power_t;
typedef enum {
ADC_RTC_DATA_OK = 0,
} adc_ll_rtc_raw_data_t;
typedef enum {
ADC_LL_CTRL_RTC = 0, ///< For ADC1 and ADC2. Select RTC controller.
ADC_LL_CTRL_ULP = 1, ///< For ADC1 and ADC2. Select ULP controller.
ADC_LL_CTRL_DIG = 2, ///< For ADC1 and ADC2. Select DIG controller.
ADC_LL_CTRL_PWDET = 3, ///< For ADC2. Select PWDET controller.
} adc_ll_controller_t;
/**
* @brief ADC digital controller (DMA mode) work mode.
*
* @note The conversion mode affects the sampling frequency:
* SINGLE_UNIT_1: When the measurement is triggered, only ADC1 is sampled once.
* SINGLE_UNIT_2: When the measurement is triggered, only ADC2 is sampled once.
* BOTH_UNIT : When the measurement is triggered, ADC1 and ADC2 are sampled at the same time.
* ALTER_UNIT : When the measurement is triggered, ADC1 or ADC2 samples alternately.
*/
typedef enum {
ADC_LL_DIGI_CONV_ONLY_ADC1 = 0, // Only use ADC1 for conversion
ADC_LL_DIGI_CONV_ONLY_ADC2 = 1, // Only use ADC2 for conversion
ADC_LL_DIGI_CONV_BOTH_UNIT = 2, // Use Both ADC1 and ADC2 for conversion simultaneously
ADC_LL_DIGI_CONV_ALTER_UNIT = 3 // Use both ADC1 and ADC2 for conversion by turn. e.g. ADC1 -> ADC2 -> ADC1 -> ADC2 .....
} adc_ll_digi_convert_mode_t;
//Need a unit test for bit_width
typedef struct {
union {
struct {
uint8_t atten: 2;
uint8_t bit_width: 2; //ADC resolution. 0: 9 bit; 1: 10 bit; 2: 11 bit; 3: 12 bit
uint8_t channel: 4;
};
uint8_t val;
};
} __attribute__((packed)) adc_ll_digi_pattern_table_t;
typedef enum {
ADC_HALL_CTRL_ULP = 0x0,/*!< Hall sensor controlled by ULP */
ADC_HALL_CTRL_RTC = 0x1 /*!< Hall sensor controlled by RTC */
} adc_ll_hall_controller_t ;
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* Set adc fsm interval parameter for digital controller. These values are fixed for same platforms.
*
* @param rst_wait cycles between DIG ADC controller reset ADC sensor and start ADC sensor.
* @param start_wait Delay time after open xpd.
* @param standby_wait Delay time to close xpd.
*/
static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait)
{
// Internal FSM reset wait time
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_fsm, rstb_wait, rst_wait);
// Internal FSM start wait time
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_fsm, start_wait, start_wait);
// Internal FSM standby wait time
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_fsm, standby_wait, standby_wait);
}
/**
* Set adc sample cycle.
*
* @note Normally, please use default value.
* @param sample_cycle The number of ADC sampling cycles. Range: 1 ~ 7.
*/
static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_fsm, sample_cycle, sample_cycle);
}
/**
* ADC module clock division factor setting. ADC clock divided from APB clock.
*
* @param div Division factor.
*/
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
/* ADC clock divided from APB clk, e.g. 80 / 2 = 40Mhz, */
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_ctrl, sar_clk_div, div);
}
/**
* Set adc max conversion number for digital controller.
* If the number of ADC conversion is equal to the maximum, the conversion is stopped.
*
* @param meas_num Max conversion number. Range: 0 ~ 255.
*/
static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(SYSCON.saradc_ctrl2, max_meas_num, meas_num);
}
/**
* Enable max conversion number detection for digital controller.
* If the number of ADC conversion is equal to the maximum, the conversion is stopped.
*/
static inline void adc_ll_digi_convert_limit_enable(void)
{
SYSCON.saradc_ctrl2.meas_num_limit = 1;
}
/**
* Disable max conversion number detection for digital controller.
* If the number of ADC conversion is equal to the maximum, the conversion is stopped.
*/
static inline void adc_ll_digi_convert_limit_disable(void)
{
SYSCON.saradc_ctrl2.meas_num_limit = 0;
}
/**
* Set adc conversion mode for digital controller.
*
* @note ESP32 only support ADC1 single mode.
* @note For `data_sar_sel` register:
* 1: [15] unit, [14:11] channel, [10:0] data, 11-bit-width at most. Only work under `ADC_LL_DIGI_CONV_BOTH_UNIT` or `ADC_LL_DIGI_CONV_ALTER_UNIT` mode.
* 0: [15:12] channel, [11:0] data, 12-bit-width at most. Only work under `ADC_LL_DIGI_CONV_ONLY_ADC1` or `ADC_LL_DIGI_CONV_ONLY_ADC2` mode
*
* @param mode Conversion mode select.
*/
static inline void adc_ll_digi_set_convert_mode(adc_ll_digi_convert_mode_t mode)
{
if (mode == ADC_LL_DIGI_CONV_ONLY_ADC1) {
SYSCON.saradc_ctrl.work_mode = 0;
SYSCON.saradc_ctrl.sar_sel = 0;
SYSCON.saradc_ctrl.data_sar_sel = 0;
} else if (mode == ADC_LL_DIGI_CONV_ONLY_ADC2) {
SYSCON.saradc_ctrl.work_mode = 0;
SYSCON.saradc_ctrl.sar_sel = 1;
SYSCON.saradc_ctrl.data_sar_sel = 0;
} else if (mode == ADC_LL_DIGI_CONV_BOTH_UNIT) {
SYSCON.saradc_ctrl.work_mode = 1;
SYSCON.saradc_ctrl.data_sar_sel = 1;
} else if (mode == ADC_LL_DIGI_CONV_ALTER_UNIT) {
SYSCON.saradc_ctrl.work_mode = 2;
SYSCON.saradc_ctrl.data_sar_sel = 1;
}
}
/**
* ADC module Digital output data invert or not.
*
* @prarm adc_n ADC unit.
*/
static inline void adc_ll_digi_output_invert(adc_ll_num_t adc_n, bool inv_en)
{
if (adc_n == ADC_NUM_1) {
SYSCON.saradc_ctrl2.sar1_inv = inv_en; // Enable / Disable ADC data invert
} else { // adc_n == ADC_NUM_2
SYSCON.saradc_ctrl2.sar2_inv = inv_en; // Enable / Disable ADC data invert
}
}
/**
* Set I2S DMA data source for digital controller.
*
* @param src 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix
*/
static inline void adc_ll_digi_set_data_source(bool src)
{
SYSCON.saradc_ctrl.data_to_i2s = src;
}
/**
* Set pattern table length for digital controller.
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
* resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
* pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself.
*
* @param adc_n ADC unit.
* @param patt_len Items range: 1 ~ 16.
*/
static inline void adc_ll_digi_set_pattern_table_len(adc_ll_num_t adc_n, uint32_t patt_len)
{
if (adc_n == ADC_NUM_1) {
SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1;
} else { // adc_n == ADC_NUM_2
SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1;
}
}
/**
* Set pattern table lenth for digital controller.
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
* resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
* pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself.
*
* @param adc_n ADC unit.
* @param pattern_index Items index. Range: 0 ~ 15.
* @param pattern Stored conversion rules, see ``adc_digi_pattern_table_t``.
*/
static inline void adc_ll_digi_set_pattern_table(adc_ll_num_t adc_n, uint32_t pattern_index, adc_digi_pattern_config_t table)
{
uint32_t tab;
uint8_t index = pattern_index / 4;
uint8_t offset = (pattern_index % 4) * 8;
adc_ll_digi_pattern_table_t pattern = {0};
uint8_t bit_width;
switch (table.bit_width) {
case 9:
bit_width = 0x0;
break;
case 10:
bit_width = 0x1;
break;
case 11:
bit_width = 0x2;
break;
case 12:
bit_width = 0x3;
break;
default:
bit_width = 0x3;
}
pattern.val = (table.atten & 0x3) | ((bit_width) << 2) | ((table.channel & 0xF) << 4);
if (table.unit == ADC_NUM_1) {
tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value
tab &= (~(0xFF000000 >> offset)); // clear old data
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back
} else { // adc_n == ADC_NUM_2
tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value
tab &= (~(0xFF000000 >> offset)); // clear old data
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back
}
}
/**
* Reset the pattern table pointer, then take the measurement rule from table header in next measurement.
*
* @param adc_n ADC unit.
*/
static inline void adc_ll_digi_clear_pattern_table(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
SYSCON.saradc_ctrl.sar1_patt_p_clear = 1;
SYSCON.saradc_ctrl.sar1_patt_p_clear = 0;
} else { // adc_n == ADC_NUM_2
SYSCON.saradc_ctrl.sar2_patt_p_clear = 1;
SYSCON.saradc_ctrl.sar2_patt_p_clear = 0;
}
}
/**
* Disable clock for ADC digital controller.
* @note Not used for esp32
*/
static inline void adc_ll_digi_controller_clk_disable(void)
{
//Leave here for compatibility
}
/*---------------------------------------------------------------
PWDET(Power detect) controller setting
---------------------------------------------------------------*/
/**
* Set adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @param cct Range: 0 ~ 7.
*/
static inline void adc_ll_pwdet_set_cct(uint32_t cct)
{
/* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */
SENS.sar_start_force.sar2_pwdet_cct = cct;
}
/**
* Get adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @return cct Range: 0 ~ 7.
*/
static inline uint32_t adc_ll_pwdet_get_cct(void)
{
/* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */
return SENS.sar_start_force.sar2_pwdet_cct;
}
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
/**
* ADC SAR clock division factor setting. ADC SAR clock divided from `RTC_FAST_CLK`.
*
* @param div Division factor.
*/
static inline void adc_ll_set_sar_clk_div(adc_ll_num_t adc_n, uint32_t div)
{
if (adc_n == ADC_NUM_1) {
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_read_ctrl, sar1_clk_div, div);
} else { // adc_n == ADC_NUM_2
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_read_ctrl2, sar2_clk_div, div);
}
}
/**
* Set adc output data format for RTC controller.
*
* @param adc_n ADC unit.
* @param bits Output data bits width option, see ``adc_bits_width_t``.
*/
static inline void adc_ll_rtc_set_output_format(adc_ll_num_t adc_n, adc_bits_width_t bits)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_start_force.sar1_bit_width = bits;
SENS.sar_read_ctrl.sar1_sample_bit = bits;
} else { // adc_n == ADC_NUM_2
SENS.sar_start_force.sar2_bit_width = bits;
SENS.sar_read_ctrl2.sar2_sample_bit = bits;
}
}
/**
* Enable adc channel to start convert.
*
* @note Only one channel can be selected in once measurement.
*
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_meas_start1.sar1_en_pad = (1 << channel); //only one channel is selected.
} else { // adc_n == ADC_NUM_2
SENS.sar_meas_start2.sar2_en_pad = (1 << channel); //only one channel is selected.
}
}
/**
* Disable adc channel to start convert.
*
* @note Only one channel can be selected in once measurement.
*
* @param adc_n ADC unit.
*/
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_meas_start1.sar1_en_pad = 0; //only one channel is selected.
} else { // adc_n == ADC_NUM_2
SENS.sar_meas_start2.sar2_en_pad = 0; //only one channel is selected.
}
}
/**
* Start conversion once by software for RTC controller.
*
* @note It may be block to wait conversion idle for ADC1.
*
* @param adc_n ADC unit.
* @param channel ADC channel number for each ADCn.
*/
static inline void adc_ll_rtc_start_convert(adc_ll_num_t adc_n, int channel)
{
if (adc_n == ADC_NUM_1) {
while (HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_slave_addr1, meas_status) != 0) {}
SENS.sar_meas_start1.meas1_start_sar = 0;
SENS.sar_meas_start1.meas1_start_sar = 1;
} else { // adc_n == ADC_NUM_2
SENS.sar_meas_start2.meas2_start_sar = 0; //start force 0
SENS.sar_meas_start2.meas2_start_sar = 1; //start force 1
}
}
/**
* Check the conversion done flag for each ADCn for RTC controller.
*
* @param adc_n ADC unit.
* @return
* -true : The conversion process is finish.
* -false : The conversion process is not finish.
*/
static inline bool adc_ll_rtc_convert_is_done(adc_ll_num_t adc_n)
{
bool ret = true;
if (adc_n == ADC_NUM_1) {
ret = (bool)SENS.sar_meas_start1.meas1_done_sar;
} else { // adc_n == ADC_NUM_2
ret = (bool)SENS.sar_meas_start2.meas2_done_sar;
}
return ret;
}
/**
* Get the converted value for each ADCn for RTC controller.
*
* @param adc_n ADC unit.
* @return
* - Converted value.
*/
static inline int adc_ll_rtc_get_convert_value(adc_ll_num_t adc_n)
{
int ret_val = 0;
if (adc_n == ADC_NUM_1) {
ret_val = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_meas_start1, meas1_data_sar);
} else { // adc_n == ADC_NUM_2
ret_val = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_meas_start2, meas2_data_sar);
}
return ret_val;
}
/**
* ADC module RTC output data invert or not.
*
* @param adc_n ADC unit.
*/
static inline void adc_ll_rtc_output_invert(adc_ll_num_t adc_n, bool inv_en)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_read_ctrl.sar1_data_inv = inv_en; // Enable / Disable ADC data invert
} else { // adc_n == ADC_NUM_2
SENS.sar_read_ctrl2.sar2_data_inv = inv_en; // Enable / Disable ADC data invert
}
}
/**
* Analyze whether the obtained raw data is correct.
*
* @param adc_n ADC unit.
* @param raw_data ADC raw data input (convert value).
* @return
* - 0: The data is correct to use.
*/
static inline adc_ll_rtc_raw_data_t adc_ll_rtc_analysis_raw_data(adc_ll_num_t adc_n, uint16_t raw_data)
{
/* ADC1 don't need check data */
return ADC_RTC_DATA_OK;
}
/**
* Set the attenuation of a particular channel on ADCn.
*/
static inline void adc_ll_set_atten(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
{
if (adc_n == ADC_NUM_1) {
SENS.sar_atten1 = ( SENS.sar_atten1 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2));
} else { // adc_n == ADC_NUM_2
SENS.sar_atten2 = ( SENS.sar_atten2 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2));
}
}
/**
* Get the attenuation of a particular channel on ADCn.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @return atten The attenuation option.
*/
static inline adc_atten_t adc_ll_get_atten(adc_ll_num_t adc_n, adc_channel_t channel)
{
if (adc_n == ADC_NUM_1) {
return (adc_atten_t)((SENS.sar_atten1 >> (channel * 2)) & 0x3);
} else {
return (adc_atten_t)((SENS.sar_atten2 >> (channel * 2)) & 0x3);
}
}
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* Set ADC module power management.
*
* @param manage Set ADC power status.
*/
static inline void adc_ll_set_power_manage(adc_ll_power_t manage)
{
/* Bit1 0:Fsm 1: SW mode
Bit0 0:SW mode power down 1: SW mode power on */
if (manage == ADC_POWER_SW_ON) {
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
} else if (manage == ADC_POWER_BY_FSM) {
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM;
} else if (manage == ADC_POWER_SW_OFF) {
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD;
}
}
/**
* Set ADC module controller.
* There are five SAR ADC controllers:
* Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes;
* Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep;
* the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2.
*
* @param adc_n ADC unit.
* @param ctrl ADC controller.
*/
static inline void adc_ll_set_controller(adc_ll_num_t adc_n, adc_ll_controller_t ctrl)
{
if (adc_n == ADC_NUM_1) {
switch ( ctrl ) {
case ADC_LL_CTRL_RTC:
SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power.
SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
break;
case ADC_LL_CTRL_ULP:
SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
SENS.sar_meas_start1.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start1.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_touch_ctrl1.xpd_hall_force = 0; // 1: SW control HALL power; 0: ULP FSM control HALL power.
SENS.sar_touch_ctrl1.hall_phase_force = 0; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
break;
case ADC_LL_CTRL_DIG:
SENS.sar_read_ctrl.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control.
SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power.
SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
break;
default:
break;
}
} else { // adc_n == ADC_NUM_2
switch ( ctrl ) {
case ADC_LL_CTRL_RTC:
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
break;
case ADC_LL_CTRL_ULP:
SENS.sar_meas_start2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
break;
case ADC_LL_CTRL_DIG:
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_read_ctrl2.sar2_dig_force = 1; // 1: Select digital control; 0: Select RTC control.
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
break;
case ADC_LL_CTRL_PWDET: // currently only used by Wi-Fi
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
SENS.sar_read_ctrl2.sar2_pwdet_force = 1; // 1: Select power detect control; 0: Select RTC control.
SYSCON.saradc_ctrl.sar2_mux = 0; // 1: Select digital control; 0: Select power detect control.
break;
default:
break;
}
}
}
/**
* Close ADC AMP module if don't use it for power save.
*/
static inline void adc_ll_amp_disable(void)
{
//channel is set in the convert function
SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD;
//disable FSM, it's only used by the LNA.
SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_meas_wait1, sar_amp_wait1, 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_meas_wait1, sar_amp_wait2, 1);
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_meas_wait2, sar_amp_wait3, 1);
}
/*---------------------------------------------------------------
Hall sensor setting
---------------------------------------------------------------*/
/**
* Enable hall sensor.
*/
static inline void adc_ll_hall_enable(void)
{
RTCIO.hall_sens.xpd_hall = 1;
}
/**
* Disable hall sensor.
*/
static inline void adc_ll_hall_disable(void)
{
RTCIO.hall_sens.xpd_hall = 0;
}
/**
* Reverse phase of hall sensor.
*/
static inline void adc_ll_hall_phase_enable(void)
{
RTCIO.hall_sens.hall_phase = 1;
}
/**
* Don't reverse phase of hall sensor.
*/
static inline void adc_ll_hall_phase_disable(void)
{
RTCIO.hall_sens.hall_phase = 0;
}
/**
* Set hall sensor controller.
*
* @param hall_ctrl Hall controller.
*/
static inline void adc_ll_set_hall_controller(adc_ll_hall_controller_t hall_ctrl)
{
SENS.sar_touch_ctrl1.xpd_hall_force = hall_ctrl; // 1: SW control HALL power; 0: ULP FSM control HALL power.
SENS.sar_touch_ctrl1.hall_phase_force = hall_ctrl; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
}
/**
* Output ADC internal reference voltage to channels, only available for ADC2 on ESP32.
*
* This function routes the internal reference voltage of ADCn to one of
* ADC2's channels. This reference voltage can then be manually measured
* for calibration purposes.
*
* @param[in] adc ADC unit select
* @param[in] channel ADC2 channel number
* @param[in] en Enable/disable the reference voltage output
*/
static inline void adc_ll_vref_output(adc_ll_num_t adc, adc_channel_t channel, bool en)
{
if (adc != ADC_NUM_2) return;
if (en) {
RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode
//set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2)
RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels
//set ent
RTCCNTL.test_mux.ent_rtc = 1;
//set sar2_en_test
SENS.sar_start_force.sar2_en_test = 1;
//set sar2 en force
SENS.sar_meas_start2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW
//set en_pad for channels 7,8,9 (bits 0x380)
SENS.sar_meas_start2.sar2_en_pad = 1 << channel;
} else {
RTCCNTL.test_mux.dtest_rtc = 0; //Config test mux to route v_ref to ADC2 Channels
//set ent
RTCCNTL.test_mux.ent_rtc = 0;
//set sar2_en_test
SENS.sar_start_force.sar2_en_test = 0;
//set sar2 en force
SENS.sar_meas_start2.sar2_en_pad_force = 0; //Pad bitmap controlled by SW
//set en_pad for channels 7,8,9 (bits 0x380)
SENS.sar_meas_start2.sar2_en_pad = 0;
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,141 @@
// Copyright 2020-2021 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.
#pragma once
#include "soc/hwcrypto_reg.h"
#include "soc/dport_access.h"
#include "hal/aes_types.h"
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief State of AES accelerator, busy or idle
*
*/
typedef enum {
ESP_AES_STATE_BUSY = 0, /* Transform in progress */
ESP_AES_STATE_IDLE, /* AES accelerator is idle */
} esp_aes_state_t;
/**
* @brief Write the encryption/decryption key to hardware
*
* @param key Key to be written to the AES hardware
* @param key_word_len Number of words in the key
*
* @return Number of bytes written to hardware, used for fault injection check,
* if a write was skipped then this sum is likely to be wrong
*/
static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len)
{
/* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
volatile uint8_t key_bytes_in_hardware = 0;
/* Memcpy to avoid potential unaligned access */
uint32_t key_word;
for (int i = 0; i < key_word_len; i++) {
memcpy(&key_word, key + 4 * i, 4);
DPORT_REG_WRITE(AES_KEY_BASE + i * 4, key_word);
key_bytes_in_hardware += 4;
}
return key_bytes_in_hardware;
}
/**
* @brief Sets the mode
*
* @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0
* @param key_bytes Number of bytes in the key
*/
static inline void aes_ll_set_mode(int mode, uint8_t key_bytes)
{
const uint32_t MODE_DECRYPT_BIT = 4;
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
/* See TRM for the mapping between keylength and mode bit */
DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2));
}
/**
* @brief Writes message block to AES hardware
*
* @param input Block to be written
*/
static inline void aes_ll_write_block(const uint8_t *input)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t i0;
uint32_t i1;
uint32_t i2;
uint32_t i3;
/* Storing i0,i1,i2,i3 in registers not an array
helps a lot with optimisations at -Os level */
i0 = input_words[0];
DPORT_REG_WRITE(AES_TEXT_BASE, i0);
i1 = input_words[1];
DPORT_REG_WRITE(AES_TEXT_BASE + 4, i1);
i2 = input_words[2];
DPORT_REG_WRITE(AES_TEXT_BASE + 8, i2);
i3 = input_words[3];
DPORT_REG_WRITE(AES_TEXT_BASE + 12, i3);
}
/**
* @brief Read the AES block
*
* @note If a transform was ran then this is the output
*
* @param output the output of the transform, length = AES_BLOCK_BYTES
*/
static inline void aes_ll_read_block(void *output)
{
uint32_t *output_words = (uint32_t *)output;
esp_dport_access_read_buffer(output_words, AES_TEXT_BASE, AES_BLOCK_WORDS);
}
/**
* @brief Starts block transform
*
*/
static inline void aes_ll_start_transform(void)
{
DPORT_REG_WRITE(AES_START_REG, 1);
}
/**
* @brief Read state of AES accelerator
*
* @return esp_aes_state_t
*/
static inline esp_aes_state_t aes_ll_get_state(void)
{
return DPORT_REG_READ(AES_IDLE_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,139 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#warning hal/can_hal.h is deprecated, please use hal/twai_hal.h instead
#include "hal/twai_hal.h"
#include "hal/can_types.h"
/* ------------------------- Defines and Typedefs --------------------------- */
//Error active interrupt related
#define CAN_HAL_EVENT_BUS_OFF TWAI_HAL_EVENT_BUS_OFF
#define CAN_HAL_EVENT_BUS_RECOV_CPLT TWAI_HAL_EVENT_BUS_RECOV_CPLT
#define CAN_HAL_EVENT_BUS_RECOV_PROGRESS TWAI_HAL_EVENT_BUS_RECOV_PROGRESS
#define CAN_HAL_EVENT_ABOVE_EWL TWAI_HAL_EVENT_ABOVE_EWL
#define CAN_HAL_EVENT_BELOW_EWL TWAI_HAL_EVENT_BELOW_EWL
#define CAN_HAL_EVENT_ERROR_PASSIVE TWAI_HAL_EVENT_ERROR_PASSIVE
#define CAN_HAL_EVENT_ERROR_ACTIVE TWAI_HAL_EVENT_ERROR_ACTIVE
#define CAN_HAL_EVENT_BUS_ERR TWAI_HAL_EVENT_BUS_ERR
#define CAN_HAL_EVENT_ARB_LOST TWAI_HAL_EVENT_ARB_LOST
#define CAN_HAL_EVENT_RX_BUFF_FRAME TWAI_HAL_EVENT_RX_BUFF_FRAME
#define CAN_HAL_EVENT_TX_BUFF_FREE TWAI_HAL_EVENT_TX_BUFF_FREE
typedef twai_hal_context_t can_hal_context_t;
typedef twai_hal_frame_t can_hal_frame_t;
/* ---------------------------- Init and Config ----------------------------- */
static inline bool can_hal_init(can_hal_context_t *hal_ctx){
return twai_hal_init(hal_ctx);
}
static inline void can_hal_deinit(can_hal_context_t *hal_ctx)
{
twai_hal_deinit(hal_ctx);
}
static inline void can_hal_configure(can_hal_context_t *hal_ctx, const can_timing_config_t *t_config, const can_filter_config_t *f_config, uint32_t intr_mask, uint32_t clkout_divider)
{
twai_hal_configure(hal_ctx, t_config, f_config, intr_mask, clkout_divider);
}
/* -------------------------------- Actions --------------------------------- */
static inline void can_hal_start(can_hal_context_t *hal_ctx, can_mode_t mode)
{
twai_hal_start(hal_ctx, mode);
}
static inline void can_hal_stop(can_hal_context_t *hal_ctx)
{
twai_hal_stop(hal_ctx);
}
static inline void can_hal_start_bus_recovery(can_hal_context_t *hal_ctx)
{
twai_hal_start_bus_recovery(hal_ctx);
}
static inline uint32_t can_hal_get_tec(can_hal_context_t *hal_ctx)
{
return twai_hal_get_tec(hal_ctx);
}
static inline uint32_t can_hal_get_rec(can_hal_context_t *hal_ctx)
{
return twai_hal_get_rec(hal_ctx);
}
static inline uint32_t can_hal_get_rx_msg_count(can_hal_context_t *hal_ctx)
{
return twai_hal_get_rx_msg_count(hal_ctx);
}
static inline bool can_hal_check_last_tx_successful(can_hal_context_t *hal_ctx)
{
return twai_hal_check_last_tx_successful(hal_ctx);
}
static inline bool can_hal_check_state_flags(can_hal_context_t *hal_ctx, uint32_t check_flags)
{
return twai_hal_check_state_flags(hal_ctx, check_flags);
}
/* ----------------------------- Event Handling ----------------------------- */
static inline uint32_t can_hal_decode_interrupt_events(can_hal_context_t *hal_ctx) {
return twai_hal_decode_interrupt(hal_ctx);
}
/* ------------------------------- TX and RX -------------------------------- */
static inline void can_hal_format_frame(const can_message_t *message, can_hal_frame_t *frame)
{
twai_hal_format_frame(message, frame);
}
static inline void can_hal_parse_frame(can_hal_frame_t *frame, can_message_t *message)
{
twai_hal_parse_frame(frame, message);
}
static inline void can_hal_set_tx_buffer_and_transmit(can_hal_context_t *hal_ctx, can_hal_frame_t *tx_frame)
{
twai_hal_set_tx_buffer_and_transmit(hal_ctx, tx_frame);
}
static inline void can_hal_read_rx_buffer_and_clear(can_hal_context_t *hal_ctx, can_hal_frame_t *rx_frame)
{
twai_hal_read_rx_buffer_and_clear(hal_ctx, rx_frame);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,254 @@
// 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for CAN
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#warning hal/can_ll.h is deprecated, please use hal/twai_ll.h instead
#include "hal/twai_ll.h"
#include "hal/can_types.h"
#include "soc/can_periph.h"
/* ------------------------- Defines and Typedefs --------------------------- */
#define CAN_LL_STATUS_RBS TWAI_LL_STATUS_RBS
#define CAN_LL_STATUS_DOS TWAI_LL_STATUS_DOS
#define CAN_LL_STATUS_TBS TWAI_LL_STATUS_TBS
#define CAN_LL_STATUS_TCS TWAI_LL_STATUS_TCS
#define CAN_LL_STATUS_RS TWAI_LL_STATUS_RS
#define CAN_LL_STATUS_TS TWAI_LL_STATUS_TS
#define CAN_LL_STATUS_ES TWAI_LL_STATUS_ES
#define CAN_LL_STATUS_BS TWAI_LL_STATUS_BS
#define CAN_LL_INTR_RI TWAI_LL_INTR_RI
#define CAN_LL_INTR_TI TWAI_LL_INTR_TI
#define CAN_LL_INTR_EI TWAI_LL_INTR_EI
#define CAN_LL_INTR_EPI TWAI_LL_INTR_EPI
#define CAN_LL_INTR_ALI TWAI_LL_INTR_ALI
#define CAN_LL_INTR_BEI TWAI_LL_INTR_BEI
typedef twai_ll_frame_buffer_t can_ll_frame_buffer_t;
/* ---------------------------- Mode Register ------------------------------- */
static inline void can_ll_enter_reset_mode(can_dev_t *hw)
{
twai_ll_enter_reset_mode(hw);
}
static inline void can_ll_exit_reset_mode(can_dev_t *hw)
{
twai_ll_exit_reset_mode(hw);
}
static inline bool can_ll_is_in_reset_mode(can_dev_t *hw)
{
return twai_ll_is_in_reset_mode(hw);
}
static inline void can_ll_set_mode(can_dev_t *hw, can_mode_t mode)
{
twai_ll_set_mode(hw, mode);
}
/* --------------------------- Command Register ----------------------------- */
static inline void can_ll_set_cmd_tx(can_dev_t *hw)
{
twai_ll_set_cmd_tx(hw);
}
static inline void can_ll_set_cmd_tx_single_shot(can_dev_t *hw)
{
twai_ll_set_cmd_tx_single_shot(hw);
}
static inline void can_ll_set_cmd_abort_tx(can_dev_t *hw)
{
twai_ll_set_cmd_abort_tx(hw);
}
static inline void can_ll_set_cmd_release_rx_buffer(can_dev_t *hw)
{
twai_ll_set_cmd_release_rx_buffer(hw);
}
static inline void can_ll_set_cmd_clear_data_overrun(can_dev_t *hw)
{
twai_ll_set_cmd_clear_data_overrun(hw);
}
static inline void can_ll_set_cmd_self_rx_request(can_dev_t *hw)
{
twai_ll_set_cmd_self_rx_request(hw);
}
static inline void can_ll_set_cmd_self_rx_single_shot(can_dev_t *hw)
{
twai_ll_set_cmd_self_rx_single_shot(hw);
}
/* --------------------------- Status Register ------------------------------ */
static inline uint32_t can_ll_get_status(can_dev_t *hw)
{
return twai_ll_get_status(hw);
}
static inline bool can_ll_is_fifo_overrun(can_dev_t *hw)
{
return twai_ll_is_fifo_overrun(hw);
}
static inline bool can_ll_is_last_tx_successful(can_dev_t *hw)
{
return twai_ll_is_last_tx_successful(hw);
}
/* -------------------------- Interrupt Register ---------------------------- */
static inline uint32_t can_ll_get_and_clear_intrs(can_dev_t *hw)
{
return twai_ll_get_and_clear_intrs(hw);
}
/* ----------------------- Interrupt Enable Register ------------------------ */
static inline void can_ll_set_enabled_intrs(can_dev_t *hw, uint32_t intr_mask)
{
twai_ll_set_enabled_intrs(hw, intr_mask);
}
/* ------------------------ Bus Timing Registers --------------------------- */
static inline void can_ll_set_bus_timing(can_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling)
{
twai_ll_set_bus_timing(hw, brp, sjw, tseg1, tseg2, triple_sampling);
}
/* ----------------------------- ALC Register ------------------------------- */
static inline void can_ll_clear_arb_lost_cap(can_dev_t *hw)
{
twai_ll_clear_arb_lost_cap(hw);
}
/* ----------------------------- ECC Register ------------------------------- */
static inline void can_ll_clear_err_code_cap(can_dev_t *hw)
{
twai_ll_clear_err_code_cap(hw);
}
/* ----------------------------- EWL Register ------------------------------- */
static inline void can_ll_set_err_warn_lim(can_dev_t *hw, uint32_t ewl)
{
twai_ll_set_err_warn_lim(hw, ewl);
}
static inline uint32_t can_ll_get_err_warn_lim(can_dev_t *hw)
{
return twai_ll_get_err_warn_lim(hw);
}
/* ------------------------ RX Error Count Register ------------------------- */
static inline uint32_t can_ll_get_rec(can_dev_t *hw)
{
return twai_ll_get_rec(hw);
}
static inline void can_ll_set_rec(can_dev_t *hw, uint32_t rec)
{
twai_ll_set_rec(hw, rec);
}
/* ------------------------ TX Error Count Register ------------------------- */
static inline uint32_t can_ll_get_tec(can_dev_t *hw)
{
return twai_ll_get_tec(hw);
}
static inline void can_ll_set_tec(can_dev_t *hw, uint32_t tec)
{
twai_ll_set_tec(hw, tec);
}
/* ---------------------- Acceptance Filter Registers ----------------------- */
static inline void can_ll_set_acc_filter(can_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
{
twai_ll_set_acc_filter(hw, code, mask, single_filter);
}
/* ------------------------- TX/RX Buffer Registers ------------------------- */
static inline void can_ll_set_tx_buffer(can_dev_t *hw, can_ll_frame_buffer_t *tx_frame)
{
twai_ll_set_tx_buffer(hw, tx_frame);
}
static inline void can_ll_get_rx_buffer(can_dev_t *hw, can_ll_frame_buffer_t *rx_frame)
{
twai_ll_get_rx_buffer(hw, rx_frame);
}
static inline void can_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const uint8_t *data,
uint32_t flags, can_ll_frame_buffer_t *tx_frame)
{
twai_ll_format_frame_buffer(id, dlc, data, flags, tx_frame);
}
static inline void can_ll_prase_frame_buffer(can_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
uint8_t *data, uint32_t *flags)
{
twai_ll_prase_frame_buffer(rx_frame, id, dlc, data, flags);
}
/* ----------------------- RX Message Count Register ------------------------ */
static inline uint32_t can_ll_get_rx_msg_count(can_dev_t *hw)
{
return twai_ll_get_rx_msg_count(hw);
}
/* ------------------------- Clock Divider Register ------------------------- */
static inline void can_ll_set_clkout(can_dev_t *hw, uint32_t divider)
{
twai_ll_set_clkout(hw, divider);
}
static inline void can_ll_enable_extended_reg_layout(can_dev_t *hw)
{
twai_ll_enable_extended_reg_layout(hw);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,68 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#warning hal/can_types.h is deprecated, please use hal/twai_types.h instead
#include "hal/twai_types.h"
/* ---------------------------- Compatibility ------------------------------- */
#define CAN_EXTD_ID_MASK TWAI_EXTD_ID_MASK
#define CAN_STD_ID_MASK TWAI_STD_ID_MASK
#define CAN_FRAME_MAX_DLC TWAI_FRAME_MAX_DLC
#define CAN_FRAME_EXTD_ID_LEN_BYTES TWAI_FRAME_EXTD_ID_LEN_BYTES
#define CAN_FRAME_STD_ID_LEN_BYTES TWAI_FRAME_STD_ID_LEN_BYTES
#define CAN_ERR_PASS_THRESH TWAI_ERR_PASS_THRESH
#define CAN_MSG_FLAG_NONE TWAI_MSG_FLAG_NONE
#define CAN_MSG_FLAG_EXTD TWAI_MSG_FLAG_EXTD
#define CAN_MSG_FLAG_RTR TWAI_MSG_FLAG_RTR
#define CAN_MSG_FLAG_SS TWAI_MSG_FLAG_SS
#define CAN_MSG_FLAG_SELF TWAI_MSG_FLAG_SELF
#define CAN_MSG_FLAG_DLC_NON_COMP TWAI_MSG_FLAG_DLC_NON_COMP
#if (SOC_TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN >= 2)
#define CAN_TIMING_CONFIG_12_5KBITS() TWAI_TIMING_CONFIG_12_5KBITS()
#define CAN_TIMING_CONFIG_16KBITS() TWAI_TIMING_CONFIG_16KBITS()
#define CAN_TIMING_CONFIG_20KBITS() TWAI_TIMING_CONFIG_20KBITS()
#endif
#define CAN_TIMING_CONFIG_25KBITS() TWAI_TIMING_CONFIG_25KBITS()
#define CAN_TIMING_CONFIG_50KBITS() TWAI_TIMING_CONFIG_50KBITS()
#define CAN_TIMING_CONFIG_100KBITS() TWAI_TIMING_CONFIG_100KBITS()
#define CAN_TIMING_CONFIG_125KBITS() TWAI_TIMING_CONFIG_125KBITS()
#define CAN_TIMING_CONFIG_250KBITS() TWAI_TIMING_CONFIG_250KBITS()
#define CAN_TIMING_CONFIG_500KBITS() TWAI_TIMING_CONFIG_500KBITS()
#define CAN_TIMING_CONFIG_800KBITS() TWAI_TIMING_CONFIG_800KBITS()
#define CAN_TIMING_CONFIG_1MBITS() TWAI_TIMING_CONFIG_1MBITS()
#define CAN_FILTER_CONFIG_ACCEPT_ALL() TWAI_FILTER_CONFIG_ACCEPT_ALL()
typedef twai_mode_t can_mode_t;
#define CAN_MODE_NORMAL TWAI_MODE_NORMAL
#define CAN_MODE_NO_ACK TWAI_MODE_NO_ACK
#define CAN_MODE_LISTEN_ONLY TWAI_MODE_LISTEN_ONLY
typedef twai_message_t can_message_t;
typedef twai_timing_config_t can_timing_config_t;
typedef twai_filter_config_t can_filter_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,276 @@
// Copyright 2015-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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/periph_defs.h"
#include "soc/dport_reg.h"
#include "soc/dport_access.h"
static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
{
switch (periph) {
case PERIPH_LEDC_MODULE:
return DPORT_LEDC_CLK_EN;
case PERIPH_UART0_MODULE:
return DPORT_UART_CLK_EN;
case PERIPH_UART1_MODULE:
return DPORT_UART1_CLK_EN;
case PERIPH_UART2_MODULE:
return DPORT_UART2_CLK_EN;
case PERIPH_I2C0_MODULE:
return DPORT_I2C_EXT0_CLK_EN;
case PERIPH_I2C1_MODULE:
return DPORT_I2C_EXT1_CLK_EN;
case PERIPH_I2S0_MODULE:
return DPORT_I2S0_CLK_EN;
case PERIPH_I2S1_MODULE:
return DPORT_I2S1_CLK_EN;
case PERIPH_TIMG0_MODULE:
return DPORT_TIMERGROUP_CLK_EN;
case PERIPH_TIMG1_MODULE:
return DPORT_TIMERGROUP1_CLK_EN;
case PERIPH_PWM0_MODULE:
return DPORT_PWM0_CLK_EN;
case PERIPH_PWM1_MODULE:
return DPORT_PWM1_CLK_EN;
case PERIPH_UHCI0_MODULE:
return DPORT_UHCI0_CLK_EN;
case PERIPH_UHCI1_MODULE:
return DPORT_UHCI1_CLK_EN;
case PERIPH_RMT_MODULE:
return DPORT_RMT_CLK_EN;
case PERIPH_PCNT_MODULE:
return DPORT_PCNT_CLK_EN;
case PERIPH_SPI_MODULE:
return DPORT_SPI01_CLK_EN;
case PERIPH_HSPI_MODULE:
return DPORT_SPI2_CLK_EN;
case PERIPH_VSPI_MODULE:
return DPORT_SPI3_CLK_EN;
case PERIPH_SPI_DMA_MODULE:
return DPORT_SPI_DMA_CLK_EN;
case PERIPH_SDMMC_MODULE:
return DPORT_WIFI_CLK_SDIO_HOST_EN;
case PERIPH_SDIO_SLAVE_MODULE:
return DPORT_WIFI_CLK_SDIOSLAVE_EN;
case PERIPH_TWAI_MODULE:
return DPORT_TWAI_CLK_EN;
case PERIPH_EMAC_MODULE:
return DPORT_WIFI_CLK_EMAC_EN;
case PERIPH_RNG_MODULE:
return DPORT_WIFI_CLK_RNG_EN;
case PERIPH_WIFI_MODULE:
return DPORT_WIFI_CLK_WIFI_EN_M;
case PERIPH_BT_MODULE:
return DPORT_WIFI_CLK_BT_EN_M;
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_WIFI_CLK_WIFI_BT_COMMON_M;
case PERIPH_BT_BASEBAND_MODULE:
return DPORT_BT_BASEBAND_EN;
case PERIPH_BT_LC_MODULE:
return DPORT_BT_LC_EN;
case PERIPH_AES_MODULE:
return DPORT_PERI_EN_AES;
case PERIPH_SHA_MODULE:
return DPORT_PERI_EN_SHA;
case PERIPH_RSA_MODULE:
return DPORT_PERI_EN_RSA;
default:
return 0;
}
}
static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable)
{
switch (periph) {
case PERIPH_LEDC_MODULE:
return DPORT_LEDC_RST;
case PERIPH_UART0_MODULE:
return DPORT_UART_RST;
case PERIPH_UART1_MODULE:
return DPORT_UART1_RST;
case PERIPH_UART2_MODULE:
return DPORT_UART2_RST;
case PERIPH_I2C0_MODULE:
return DPORT_I2C_EXT0_RST;
case PERIPH_I2C1_MODULE:
return DPORT_I2C_EXT1_RST;
case PERIPH_I2S0_MODULE:
return DPORT_I2S0_RST;
case PERIPH_I2S1_MODULE:
return DPORT_I2S1_RST;
case PERIPH_TIMG0_MODULE:
return DPORT_TIMERGROUP_RST;
case PERIPH_TIMG1_MODULE:
return DPORT_TIMERGROUP1_RST;
case PERIPH_PWM0_MODULE:
return DPORT_PWM0_RST;
case PERIPH_PWM1_MODULE:
return DPORT_PWM1_RST;
case PERIPH_UHCI0_MODULE:
return DPORT_UHCI0_RST;
case PERIPH_UHCI1_MODULE:
return DPORT_UHCI1_RST;
case PERIPH_RMT_MODULE:
return DPORT_RMT_RST;
case PERIPH_PCNT_MODULE:
return DPORT_PCNT_RST;
case PERIPH_SPI_MODULE:
return DPORT_SPI01_RST;
case PERIPH_HSPI_MODULE:
return DPORT_SPI2_RST;
case PERIPH_VSPI_MODULE:
return DPORT_SPI3_RST;
case PERIPH_SPI_DMA_MODULE:
return DPORT_SPI_DMA_RST;
case PERIPH_SDMMC_MODULE:
return DPORT_SDIO_HOST_RST;
case PERIPH_SDIO_SLAVE_MODULE:
return DPORT_SDIO_RST;
case PERIPH_TWAI_MODULE:
return DPORT_TWAI_RST;
case PERIPH_EMAC_MODULE:
return DPORT_EMAC_RST;
case PERIPH_AES_MODULE:
if (enable == true) {
// Clear reset on digital signature & secure boot units, otherwise AES unit is held in reset also.
return (DPORT_PERI_EN_AES | DPORT_PERI_EN_DIGITAL_SIGNATURE | DPORT_PERI_EN_SECUREBOOT);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return DPORT_PERI_EN_AES;
}
case PERIPH_SHA_MODULE:
if (enable == true) {
// Clear reset on secure boot, otherwise SHA is held in reset
return (DPORT_PERI_EN_SHA | DPORT_PERI_EN_SECUREBOOT);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return DPORT_PERI_EN_SHA;
}
case PERIPH_RSA_MODULE:
if (enable == true) {
// Also clear reset on digital signature, otherwise RSA is held in reset
return (DPORT_PERI_EN_RSA | DPORT_PERI_EN_DIGITAL_SIGNATURE);
} else {
// Don't reset digital signature unit, as this resets AES also
return DPORT_PERI_EN_RSA;
}
default:
return 0;
}
}
static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
{
switch (periph) {
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
return DPORT_PERI_CLK_EN_REG;
case PERIPH_SDMMC_MODULE:
case PERIPH_SDIO_SLAVE_MODULE:
case PERIPH_EMAC_MODULE:
case PERIPH_RNG_MODULE:
case PERIPH_WIFI_MODULE:
case PERIPH_BT_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
case PERIPH_BT_BASEBAND_MODULE:
case PERIPH_BT_LC_MODULE:
return DPORT_WIFI_CLK_EN_REG;
default:
return DPORT_PERIP_CLK_EN_REG;
}
}
static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
{
switch (periph) {
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
return DPORT_PERI_RST_EN_REG;
case PERIPH_SDMMC_MODULE:
case PERIPH_SDIO_SLAVE_MODULE:
case PERIPH_EMAC_MODULE:
case PERIPH_RNG_MODULE:
case PERIPH_WIFI_MODULE:
case PERIPH_BT_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
case PERIPH_BT_BASEBAND_MODULE:
case PERIPH_BT_LC_MODULE:
return DPORT_CORE_RST_EN_REG;
default:
return DPORT_PERIP_RST_EN_REG;
}
}
static inline void periph_ll_enable_clk_clear_rst(periph_module_t periph)
{
DPORT_SET_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, true));
}
static inline void periph_ll_disable_clk_set_rst(periph_module_t periph)
{
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
}
static inline void IRAM_ATTR periph_ll_wifi_bt_module_enable_clk_clear_rst(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void IRAM_ATTR periph_ll_wifi_bt_module_disable_clk_set_rst(void)
{
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void periph_ll_reset(periph_module_t periph)
{
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
}
static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
{
return DPORT_REG_GET_BIT(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)) == 0 &&
DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
}
static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
{
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,188 @@
// 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.
#pragma once
#include <stdint.h>
#include "esp_attr.h"
#include "soc/soc_caps.h"
#include "xt_instr_macros.h"
#include "xtensa/config/specreg.h"
#include "xtensa/config/extreg.h"
#include "esp_bit_defs.h"
#include "xtensa/config/core.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t IRAM_ATTR cpu_ll_get_core_id(void)
{
uint32_t id;
asm volatile (
"rsr.prid %0\n"
"extui %0,%0,13,1"
:"=r"(id));
return id;
}
static inline uint32_t IRAM_ATTR cpu_ll_get_cycle_count(void)
{
uint32_t result;
RSR(CCOUNT, result);
return result;
}
static inline void IRAM_ATTR cpu_ll_set_cycle_count(uint32_t val)
{
WSR(CCOUNT, val);
}
static inline void* cpu_ll_get_sp(void)
{
void *sp;
asm volatile ("mov %0, sp;" : "=r" (sp));
return sp;
}
static inline void cpu_ll_init_hwloop(void)
{
#if XCHAL_ERRATUM_572
uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
WSR(MEMCTL, memctl);
#endif // XCHAL_ERRATUM_572
}
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
{
uint32_t en;
// Set the break address register to the appropriate PC
if (id) {
WSR(IBREAKA_1, pc);
} else {
WSR(IBREAKA_0, pc);
}
// Enable the breakpoint using the break enable register
RSR(IBREAKENABLE, en);
en |= BIT(id);
WSR(IBREAKENABLE, en);
}
static inline void cpu_ll_clear_breakpoint(int id)
{
uint32_t en = 0;
uint32_t pc = 0;
// Set the break address register to the appropriate PC
if (id) {
WSR(IBREAKA_1, pc);
} else {
WSR(IBREAKA_0, pc);
}
// Enable the breakpoint using the break enable register
RSR(IBREAKENABLE, en);
en &= ~BIT(id);
WSR(IBREAKENABLE, en);
}
static inline uint32_t cpu_ll_ptr_to_pc(const void* addr)
{
return ((uint32_t) addr);
}
static inline void* cpu_ll_pc_to_ptr(uint32_t pc)
{
return (void*) ((pc & 0x3fffffffU) | 0x40000000U);
}
static inline void cpu_ll_set_watchpoint(int id,
const void* addr,
size_t size,
bool on_read,
bool on_write)
{
uint32_t dbreakc = 0x3F;
//We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
for (int x = 0; x < 7; x++) {
if (size == (size_t)(1U << x)) {
break;
}
dbreakc <<= 1;
}
dbreakc = (dbreakc & 0x3F);
if (on_read) {
dbreakc |= BIT(30);
}
if (on_write) {
dbreakc |= BIT(31);
}
// Write the break address register and the size to control
// register.
if (id) {
WSR(DBREAKA_1, (uint32_t) addr);
WSR(DBREAKC_1, dbreakc);
} else {
WSR(DBREAKA_0, (uint32_t) addr);
WSR(DBREAKC_0, dbreakc);
}
}
static inline void cpu_ll_clear_watchpoint(int id)
{
// Clear both break address register and control register
if (id) {
WSR(DBREAKA_1, 0);
WSR(DBREAKC_1, 0);
} else {
WSR(DBREAKA_0, 0);
WSR(DBREAKC_0, 0);
}
}
static inline bool cpu_ll_is_debugger_attached(void)
{
uint32_t dcr = 0;
uint32_t reg = DSRSET;
RER(reg, dcr);
return (dcr&0x1);
}
static inline void cpu_ll_break(void)
{
__asm__ ("break 1,15");
}
static inline void cpu_ll_set_vecbase(const void* vecbase)
{
asm volatile ("wsr %0, vecbase" :: "r" (vecbase));
}
static inline void cpu_ll_waiti(void)
{
asm volatile ("waiti 0\n");
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,201 @@
// Copyright 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stdlib.h>
#include "hal/misc.h"
#include "soc/dac_periph.h"
#include "soc/rtc_io_struct.h"
#include "soc/sens_struct.h"
#include "hal/dac_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Power on dac module and start output voltage.
*
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
* @param channel DAC channel num.
*/
static inline void dac_ll_power_on(dac_channel_t channel)
{
RTCIO.pad_dac[channel].dac_xpd_force = 1;
RTCIO.pad_dac[channel].xpd_dac = 1;
}
/**
* Power done dac module and stop output voltage.
*
* @param channel DAC channel num.
*/
static inline void dac_ll_power_down(dac_channel_t channel)
{
RTCIO.pad_dac[channel].dac_xpd_force = 0;
RTCIO.pad_dac[channel].xpd_dac = 0;
}
/**
* Output voltage with value (8 bit).
*
* @param channel DAC channel num.
* @param value Output value. Value range: 0 ~ 255.
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
*/
static inline void dac_ll_update_output_value(dac_channel_t channel, uint8_t value)
{
if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
} else if (channel == DAC_CHANNEL_2) {
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(RTCIO.pad_dac[channel], dac, value);
}
}
/**
* Enable/disable the synchronization operation function of ADC1 and DAC.
*
* @note If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage.
*
* @param enable Enable or disable adc and dac synchronization function.
*/
static inline void dac_ll_rtc_sync_by_adc(bool enable)
{
SENS.sar_meas_ctrl2.sar1_dac_xpd_fsm = enable;
}
/************************************/
/* DAC cosine wave generator API's */
/************************************/
/**
* Enable cosine wave generator output.
*/
static inline void dac_ll_cw_generator_enable(void)
{
SENS.sar_dac_ctrl1.sw_tone_en = 1;
}
/**
* Disable cosine wave generator output.
*/
static inline void dac_ll_cw_generator_disable(void)
{
SENS.sar_dac_ctrl1.sw_tone_en = 0;
}
/**
* Enable the cosine wave generator of DAC channel.
*
* @param channel DAC channel num.
* @param enable
*/
static inline void dac_ll_cw_set_channel(dac_channel_t channel, bool enable)
{
if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_cw_en1 = enable;
} else if (channel == DAC_CHANNEL_2) {
SENS.sar_dac_ctrl2.dac_cw_en2 = enable;
}
}
/**
* Set frequency of cosine wave generator output.
*
* @note We know that CLK8M is about 8M, but don't know the actual value. so this freq have limited error.
* @param freq_hz CW generator frequency. Range: 130(130Hz) ~ 55000(100KHz).
*/
static inline void dac_ll_cw_set_freq(uint32_t freq)
{
uint32_t sw_freq = freq * 0xFFFF / RTC_FAST_CLK_FREQ_APPROX;
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl1, sw_fstep, (sw_freq > 0xFFFF) ? 0xFFFF : sw_freq);
}
/**
* Set the amplitude of the cosine wave generator output.
*
* @param channel DAC channel num.
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC.
*/
static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t scale)
{
if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_scale1 = scale;
} else if (channel == DAC_CHANNEL_2) {
SENS.sar_dac_ctrl2.dac_scale2 = scale;
}
}
/**
* Set the phase of the cosine wave generator output.
*
* @param channel DAC channel num.
* @param scale Phase value.
*/
static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cw_phase_t phase)
{
if (channel == DAC_CHANNEL_1) {
SENS.sar_dac_ctrl2.dac_inv1 = phase;
} else if (channel == DAC_CHANNEL_2) {
SENS.sar_dac_ctrl2.dac_inv2 = phase;
}
}
/**
* Set the voltage value of the DC component of the cosine wave generator output.
*
* @note The DC offset setting should be after phase setting.
* @note Unreasonable settings can cause the signal to be oversaturated.
* @param channel DAC channel num.
* @param offset DC value. Range: -128 ~ 127.
*/
static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
{
if (channel == DAC_CHANNEL_1) {
if (SENS.sar_dac_ctrl2.dac_inv1 == DAC_CW_PHASE_180) {
offset = 0 - offset;
}
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc1, offset ? offset : (-128 - offset));
} else if (channel == DAC_CHANNEL_2) {
if (SENS.sar_dac_ctrl2.dac_inv2 == DAC_CW_PHASE_180) {
offset = 0 - offset;
}
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_dac_ctrl2, dac_dc2, offset ? offset : (-128 - offset));
}
}
/************************************/
/* DAC DMA API's */
/************************************/
/**
* Enable/disable DAC output data from I2S DMA.
* I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
*/
static inline void dac_ll_digi_enable_dma(bool enable)
{
SENS.sar_dac_ctrl1.dac_dig_force = enable;
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,600 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* 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
******************************************************************************/
// The LL layer for ESP32 eMAC register operations
#pragma once
#include <stdint.h>
#include "hal/misc.h"
#include "hal/eth_types.h"
#include "soc/emac_dma_struct.h"
#include "soc/emac_mac_struct.h"
#include "soc/emac_ext_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Register configuration */
#define EMAC_LL_INTERFRAME_GAP_96BIT (0)
#define EMAC_LL_INTERFRAME_GAP_88BIT (1)
#define EMAC_LL_INTERFRAME_GAP_80BIT (2)
#define EMAC_LL_INTERFRAME_GAP_72BIT (3)
#define EMAC_LL_INTERFRAME_GAP_64BIT (4)
#define EMAC_LL_INTERFRAME_GAP_56BIT (5)
#define EMAC_LL_INTERFRAME_GAP_48BIT (6)
#define EMAC_LL_INTERFRAME_GAP_40BIT (7)
#define EMAC_LL_BACKOFF_LIMIT_10 (0)
#define EMAC_LL_BACKOFF_LIMIT_8 (1)
#define EMAC_LL_BACKOFF_LIMIT_4 (2)
#define EMAC_LL_BACKOFF_LIMIT_1 (3)
#define EMAC_LL_PREAMBLE_LENGTH_7 (0)
#define EMAC_LL_PREAMBLE_LENGTH_5 (1)
#define EMAC_LL_PREAMBLE_LENGTH_3 (2)
#define EMAC_LL_SOURCE_ADDR_FILTER_DISABLE (0)
#define EMAC_LL_SOURCE_ADDR_FILTER_NORMAL (2)
#define EMAC_LL_SOURCE_ADDR_FILTER_INVERSE (3)
#define EMAC_LL_CONTROL_FRAME_BLOCKALL (0)
#define EMAC_LL_CONTROL_FRAME_FORWARDALL_PAUSE (1)
#define EMAC_LL_CONTROL_FRAME_FORWARDALL (2)
#define EMAC_LL_CONTROL_FRAME_FORWARDFILT (3)
#define EMAC_LL_PAUSE_TIME 0x1648
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_256 (3)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_64 (0)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_128 (1)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_192 (2)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_256 (3)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_40 (4)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_32 (5)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_24 (6)
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_16 (7)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_64 (0)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_32 (1)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_96 (2)
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_128 (3)
#define EMAC_LL_DMA_BURST_LENGTH_1BEAT (1)
#define EMAC_LL_DMA_BURST_LENGTH_2BEAT (2)
#define EMAC_LL_DMA_BURST_LENGTH_4BEAT (4)
#define EMAC_LL_DMA_BURST_LENGTH_8BEAT (8)
#define EMAC_LL_DMA_BURST_LENGTH_16BEAT (16)
#define EMAC_LL_DMA_BURST_LENGTH_32BEAT (32)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
/* PTP register bits */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
#define EMAC_LL_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
#define EMAC_LL_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
#define EMAC_LL_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
#define EMAC_LL_DMADESC_OWNER_CPU (0)
#define EMAC_LL_DMADESC_OWNER_DMA (1)
/* Interrupt flags (referring to dmastatus register in emac_dma_struct.h) */
#define EMAC_LL_DMA_TRANSMIT_FINISH_INTR 0x00000001U
#define EMAC_LL_DMA_TRANSMIT_STOP_INTR 0x00000002U
#define EMAC_LL_DMA_TRANSMIT_BUFF_UNAVAILABLE_INTR 0x00000004U
#define EMAC_LL_DMA_TRANSMIT_TIMEOUT_INTR 0x00000008U
#define EMAC_LL_DMA_RECEIVE_OVERFLOW_INTR 0x00000010U
#define EMAC_LL_DMA_TRANSMIT_UNDERFLOW_INTR 0x00000020U
#define EMAC_LL_DMA_RECEIVE_FINISH_INTR 0x00000040U
#define EMAC_LL_DMA_RECEIVE_BUFF_UNAVAILABLE_INTR 0x00000080U
#define EMAC_LL_DMA_RECEIVE_STOP_INTR 0x00000100U
#define EMAC_LL_DMA_RECEIVE_TIMEOUT_INTR 0x00000200U
#define EMAC_LL_DMA_TRANSMIT_FIRST_BYTE_INTR 0x00000400U
#define EMAC_LL_DMA_FATAL_BUS_ERROR_INRT 0x00001000U
#define EMAC_LL_DMA_RECEIVE_FIRST_BYTE_INTR 0x00002000U
#define EMAC_LL_DMA_ABNORMAL_INTR_SUMMARY 0x00004000U
#define EMAC_LL_DMA_NORMAL_INTR_SUMMARY 0x00008000U
#define EMAC_LL_DMA_POWER_MANAGE_INTR 0x10000000U
#define EMAC_LL_DMA_TIMESTAMP_TRIGGER_INTR 0x20000000U
/* Interrupt enable (referring to dmain_en register in emac_dma_struct.h) */
#define EMAC_LL_INTR_TRANSMIT_ENABLE 0x00000001U
#define EMAC_LL_INTR_TRANSMIT_STOP_ENABLE 0x00000002U
#define EMAC_LL_INTR_TRANSMIT_BUFF_UNAVAILABLE_ENABLE 0x00000004U
#define EMAC_LL_INTR_TRANSMIT_TIMEOUT_ENABLE 0x00000008U
#define EMAC_LL_INTR_OVERFLOW_ENABLE 0x00000010U
#define EMAC_LL_INTR_UNDERFLOW_ENABLE 0x00000020U
#define EMAC_LL_INTR_RECEIVE_ENABLE 0x00000040U
#define EMAC_LL_INTR_RECEIVE_BUFF_UNAVAILABLE_ENABLE 0x00000080U
#define EMAC_LL_INTR_RECEIVE_STOP_ENABLE 0x00000100U
#define EMAC_LL_INTR_RECEIVE_TIMEOUT_ENABLE 0x00000200U
#define EMAC_LL_INTR_TRANSMIT_FIRST_BYTE_ENABLE 0x00000400U
#define EMAC_LL_INTR_FATAL_BUS_ERR_ENABLE 0x00002000U
#define EMAC_LL_INTR_RECEIVE_FIRST_BYTE_ENABLE 0x00004000U
#define EMAC_LL_INTR_ABNORMAL_SUMMARY_ENABLE 0x00008000U
#define EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE 0x00010000U
/* Enable needed interrupts (recv/recv_buf_unavailabal/normal must be enabled to make eth work) */
#define EMAC_LL_CONFIG_ENABLE_INTR_MASK (EMAC_LL_INTR_RECEIVE_ENABLE | EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE)
/************** Start of mac regs operation ********************/
/* emacgmiiaddr */
static inline void emac_ll_set_csr_clock_division(emac_mac_dev_t *mac_regs, uint32_t div_mode)
{
mac_regs->emacgmiiaddr.miicsrclk = div_mode;
}
static inline bool emac_ll_is_mii_busy(emac_mac_dev_t *mac_regs)
{
return mac_regs->emacgmiiaddr.miibusy ? true : false;
}
static inline void emac_ll_set_phy_addr(emac_mac_dev_t *mac_regs, uint32_t addr)
{
mac_regs->emacgmiiaddr.miidev = addr;
}
static inline void emac_ll_set_phy_reg(emac_mac_dev_t *mac_regs, uint32_t reg)
{
mac_regs->emacgmiiaddr.miireg = reg;
}
static inline void emac_ll_write_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->emacgmiiaddr.miiwrite = enable;
}
static inline void emac_ll_set_busy(emac_mac_dev_t *mac_regs, bool busy)
{
mac_regs->emacgmiiaddr.miibusy = busy ? 1 : 0;
}
/* gmacconfig */
static inline void emac_ll_watchdog_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.watchdog = !enable;
}
static inline void emac_ll_jabber_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.jabber = !enable;
}
static inline void emac_ll_set_inter_frame_gap(emac_mac_dev_t *mac_regs, uint32_t gap)
{
mac_regs->gmacconfig.interframegap = gap;
}
static inline void emac_ll_carrier_sense_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.disablecrs = !enable;
}
static inline void emac_ll_set_port_speed(emac_mac_dev_t *mac_regs, eth_speed_t speed)
{
if (speed == ETH_SPEED_10M || speed == ETH_SPEED_100M) {
mac_regs->gmacconfig.mii = 1; // 10_100MBPS
mac_regs->gmacconfig.fespeed = speed;
} else {
mac_regs->gmacconfig.mii = 0; // 1000MBPS
}
}
static inline void emac_ll_recv_own_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.rxown = !enable;
}
static inline void emac_ll_loopback_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.loopback = enable;
}
static inline void emac_ll_set_duplex(emac_mac_dev_t *mac_regs, eth_duplex_t duplex)
{
mac_regs->gmacconfig.duplex = duplex;
}
static inline void emac_ll_checksum_offload_mode(emac_mac_dev_t *mac_regs, eth_checksum_t mode)
{
mac_regs->gmacconfig.rxipcoffload = mode;
}
static inline void emac_ll_retry_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.retry = !enable;
}
static inline void emac_ll_auto_pad_crc_strip_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.padcrcstrip = enable;
}
static inline void emac_ll_set_back_off_limit(emac_mac_dev_t *mac_regs, uint32_t limit)
{
mac_regs->gmacconfig.backofflimit = limit;
}
static inline void emac_ll_deferral_check_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.padcrcstrip = enable;
}
static inline void emac_ll_set_preamble_length(emac_mac_dev_t *mac_regs, uint32_t len)
{
mac_regs->gmacconfig.pltf = len;
}
static inline void emac_ll_transmit_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.tx = enable;
}
static inline void emac_ll_receive_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacconfig.rx = enable;
}
/* gmacff */
static inline void emac_ll_receive_all_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.receive_all = enable;
}
static inline void emac_ll_set_src_addr_filter(emac_mac_dev_t *mac_regs, uint32_t filter)
{
mac_regs->gmacff.safe = filter;
}
static inline void emac_ll_sa_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.saif = enable;
}
static inline void emac_ll_set_pass_ctrl_frame_mode(emac_mac_dev_t *mac_regs, uint32_t mode)
{
mac_regs->gmacff.pcf = mode;
}
static inline void emac_ll_broadcast_frame_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.dbf = !enable;
}
static inline void emac_ll_pass_all_multicast_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.pam = enable;
}
static inline void emac_ll_da_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.daif = enable;
}
static inline void emac_ll_promiscuous_mode_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacff.pmode = enable;
}
/* gmacfc */
static inline void emac_ll_set_pause_time(emac_mac_dev_t *mac_regs, uint32_t time)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(mac_regs->gmacfc, pause_time, time);
}
static inline void emac_ll_zero_quanta_pause_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.dzpq = !enable;
}
static inline void emac_ll_set_pause_low_threshold(emac_mac_dev_t *mac_regs, uint32_t threshold)
{
mac_regs->gmacfc.plt = threshold;
}
static inline void emac_ll_unicast_pause_frame_detect_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.upfd = enable;
}
static inline void emac_ll_receive_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.rfce = enable;
}
static inline void emac_ll_transmit_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
{
mac_regs->gmacfc.tfce = enable;
}
static inline void emac_ll_clear(emac_mac_dev_t *mac_regs)
{
mac_regs->gmacfc.val = 0;
}
/* emacdebug */
static inline uint32_t emac_ll_transmit_frame_ctrl_status(emac_mac_dev_t *mac_regs)
{
return mac_regs->emacdebug.mactfcs;
}
static inline uint32_t emac_ll_receive_read_ctrl_state(emac_mac_dev_t *mac_regs)
{
return mac_regs->emacdebug.mtlrfrcs;
}
/* emacmiidata */
static inline void emac_ll_set_phy_data(emac_mac_dev_t *mac_regs, uint32_t data)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(mac_regs->emacmiidata, mii_data, data);
}
static inline uint32_t emac_ll_get_phy_data(emac_mac_dev_t *mac_regs)
{
return HAL_FORCE_READ_U32_REG_FIELD(mac_regs->emacmiidata, mii_data);
}
/* emacaddr0 */
static inline void emac_ll_set_addr(emac_mac_dev_t *mac_regs, const uint8_t *addr)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(mac_regs->emacaddr0high, address0_hi, (addr[5] << 8) | addr[4]);
mac_regs->emacaddr0low = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0]);
}
/*************** End of mac regs operation *********************/
/************** Start of dma regs operation ********************/
/* dmabusmode */
static inline void emac_ll_reset(emac_dma_dev_t *dma_regs)
{
dma_regs->dmabusmode.sw_rst = 1;
}
static inline bool emac_ll_is_reset_done(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmabusmode.sw_rst ? false : true;
}
/* dmarxbaseaddr / dmatxbaseaddr */
static inline void emac_ll_set_rx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
{
dma_regs->dmarxbaseaddr = addr;
}
static inline void emac_ll_set_tx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
{
dma_regs->dmatxbaseaddr = addr;
}
/* dmaoperation_mode */
static inline void emac_ll_drop_tcp_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_drop_tcpip_err_fram = !enable;
}
static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.rx_store_forward = enable;
}
static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable;
}
static inline void emac_ll_trans_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.tx_str_fwd = enable;
}
static inline void emac_ll_flush_trans_fifo_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.flush_tx_fifo = enable;
}
static inline void emac_ll_set_transmit_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
{
dma_regs->dmaoperation_mode.tx_thresh_ctrl = threshold;
}
static inline void emac_ll_start_stop_dma_transmit(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.start_stop_transmission_command = enable;
}
static inline void emac_ll_forward_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.fwd_err_frame = enable;
}
static inline void emac_ll_forward_undersized_good_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.fwd_under_gf = enable;
}
static inline void emac_ll_set_recv_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
{
dma_regs->dmaoperation_mode.rx_thresh_ctrl = threshold;
}
static inline void emac_ll_opt_second_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.opt_second_frame = enable;
}
static inline void emac_ll_start_stop_dma_receive(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmaoperation_mode.start_stop_rx = enable;
}
/* dmabusmode */
static inline void emac_ll_mixed_burst_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dmamixedburst = enable;
}
static inline void emac_ll_addr_align_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dmaaddralibea = enable;
}
static inline void emac_ll_use_separate_pbl_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.use_sep_pbl = enable;
}
static inline void emac_ll_set_rx_dma_pbl(emac_dma_dev_t *dma_regs, uint32_t pbl)
{
dma_regs->dmabusmode.rx_dma_pbl = pbl;
}
static inline void emac_ll_set_prog_burst_len(emac_dma_dev_t *dma_regs, uint32_t len)
{
dma_regs->dmabusmode.prog_burst_len = len;
}
static inline void emac_ll_enhance_desc_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.alt_desc_size = enable;
}
static inline void emac_ll_set_desc_skip_len(emac_dma_dev_t *dma_regs, uint32_t len)
{
dma_regs->dmabusmode.desc_skip_len = len;
}
static inline void emac_ll_fixed_arbitration_enable(emac_dma_dev_t *dma_regs, bool enable)
{
dma_regs->dmabusmode.dma_arb_sch = enable;
}
static inline void emac_ll_set_priority_ratio(emac_dma_dev_t *dma_regs, uint32_t ratio)
{
dma_regs->dmabusmode.pri_ratio = ratio;
}
/* dmain_en */
static inline void emac_ll_enable_all_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmain_en.val = 0xFFFFFFFF;
}
static inline void emac_ll_disable_all_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmain_en.val = 0x00000000;
}
static inline void emac_ll_enable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
{
dma_regs->dmain_en.val |= mask;
}
static inline void emac_ll_disable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
{
dma_regs->dmain_en.val &= ~mask;
}
static inline uint32_t emac_ll_get_intr_enable_status(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmain_en.val;
}
/* dmastatus */
__attribute__((always_inline)) static inline uint32_t emac_ll_get_intr_status(emac_dma_dev_t *dma_regs)
{
return dma_regs->dmastatus.val;
}
__attribute__((always_inline)) static inline void emac_ll_clear_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t bits)
{
dma_regs->dmastatus.val = bits;
}
__attribute__((always_inline)) static inline void emac_ll_clear_all_pending_intr(emac_dma_dev_t *dma_regs)
{
dma_regs->dmastatus.val = 0xFFFFFFFF;
}
/* dmatxpolldemand / dmarxpolldemand */
static inline void emac_ll_transmit_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
{
dma_regs->dmatxpolldemand = val;
}
static inline void emac_ll_receive_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
{
dma_regs->dmarxpolldemand = val;
}
/*************** End of dma regs operation *********************/
/************** Start of ext regs operation ********************/
static inline void emac_ll_clock_enable_mii(emac_ext_dev_t *ext_regs)
{
/* 0 for mii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
}
static inline void emac_ll_clock_enable_rmii_input(emac_ext_dev_t *ext_regs)
{
/* 4 for rmii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
ext_regs->ex_clk_ctrl.ext_en = 1;
ext_regs->ex_clk_ctrl.int_en = 0;
ext_regs->ex_oscclk_conf.clk_sel = 1;
}
static inline void emac_ll_clock_enable_rmii_output(emac_ext_dev_t *ext_regs)
{
/* 4 for rmii mode */
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
ext_regs->ex_clk_ctrl.ext_en = 0;
ext_regs->ex_clk_ctrl.int_en = 1;
ext_regs->ex_oscclk_conf.clk_sel = 0;
ext_regs->ex_clkout_conf.div_num = 0;
ext_regs->ex_clkout_conf.h_div_num = 0;
}
static inline void emac_ll_pause_frame_enable(emac_ext_dev_t *ext_regs, bool enable)
{
ext_regs->ex_phyinf_conf.sbd_flowctrl = enable;
}
/*************** End of ext regs operation *********************/
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,593 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* 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
******************************************************************************/
// The LL layer for ESP32 GPIO register operations
#pragma once
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/gpio_periph.h"
#include "soc/gpio_struct.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "hal/gpio_types.h"
#include "hal/misc.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get GPIO hardware instance with giving gpio num
#define GPIO_LL_GET_HW(num) (((num) == 0) ? (&GPIO) : NULL)
#define GPIO_LL_APP_CPU_INTR_ENA (BIT(0))
#define GPIO_LL_APP_CPU_NMI_INTR_ENA (BIT(1))
#define GPIO_LL_PRO_CPU_INTR_ENA (BIT(2))
#define GPIO_LL_PRO_CPU_NMI_INTR_ENA (BIT(3))
#define GPIO_LL_SDIO_EXT_INTR_ENA (BIT(4))
/**
* @brief Enable pull-up on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
/**
* @brief Disable pull-up on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
/**
* @brief Return pull-up status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s FUN_PU is true
*/
static inline bool gpio_ll_pullup_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU) ? true : false;
}
/**
* @brief Enable pull-down on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
/**
* @brief Disable pull-down on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
/**
* @brief Return pull-down status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s FUN_PD is true
*/
static inline bool gpio_ll_pulldown_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD) ? true : false;
}
/**
* @brief Enable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-sel status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_SEL is true
*/
static inline bool gpio_ll_sleep_sel_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_SEL) ? true : false;
}
/**
* @brief Disable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-pull-up status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_PU is true
*/
static inline bool gpio_ll_sleep_pullup_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PU) ? true : false;
}
/**
* @brief Enable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Return slp-pull-down status on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
* @return if GPIO gpio_num`s SLP_PD is true
*/
static inline bool gpio_ll_sleep_pulldown_is_enabled(gpio_dev_t *hw, gpio_num_t gpio_num)
{
return REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], SLP_PD) ? true : false;
}
/**
* @brief GPIO set interrupt trigger type
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param intr_type Interrupt type, select from gpio_int_type_t
*/
static inline void gpio_ll_set_intr_type(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
hw->pin[gpio_num].int_type = intr_type;
}
/**
* @brief Get GPIO interrupt status
*
* @param hw Peripheral GPIO hardware instance address.
* @param core_id interrupt core id
* @param status interrupt status
*/
static inline void gpio_ll_get_intr_status(gpio_dev_t *hw, uint32_t core_id, uint32_t *status)
{
*status = (core_id == 0) ? hw->pcpu_int : hw->acpu_int;
}
/**
* @brief Get GPIO interrupt status high
*
* @param hw Peripheral GPIO hardware instance address.
* @param core_id interrupt core id
* @param status interrupt status high
*/
static inline void gpio_ll_get_intr_status_high(gpio_dev_t *hw, uint32_t core_id, uint32_t *status)
{
*status = (core_id == 0) ? HAL_FORCE_READ_U32_REG_FIELD(hw->pcpu_int1, intr) : HAL_FORCE_READ_U32_REG_FIELD(hw->acpu_int1, intr);
}
/**
* @brief Clear GPIO interrupt status
*
* @param hw Peripheral GPIO hardware instance address.
* @param mask interrupt status clear mask
*/
static inline void gpio_ll_clear_intr_status(gpio_dev_t *hw, uint32_t mask)
{
hw->status_w1tc = mask;
}
/**
* @brief Clear GPIO interrupt status high
*
* @param hw Peripheral GPIO hardware instance address.
* @param mask interrupt status high clear mask
*/
static inline void gpio_ll_clear_intr_status_high(gpio_dev_t *hw, uint32_t mask)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->status1_w1tc, intr_st, mask);
}
/**
* @brief Enable GPIO module interrupt signal
*
* @param hw Peripheral GPIO hardware instance address.
* @param core_id Interrupt enabled CPU to corresponding ID
* @param gpio_num GPIO number. If you want to enable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
*/
static inline void gpio_ll_intr_enable_on_core(gpio_dev_t *hw, uint32_t core_id, gpio_num_t gpio_num)
{
if (core_id == 0) {
hw->pin[gpio_num].int_ena = GPIO_LL_PRO_CPU_INTR_ENA; //enable pro cpu intr
} else {
hw->pin[gpio_num].int_ena = GPIO_LL_APP_CPU_INTR_ENA; //enable pro cpu intr
}
}
/**
* @brief Disable GPIO module interrupt signal
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
*/
static inline void gpio_ll_intr_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
hw->pin[gpio_num].int_ena = 0; //disable GPIO intr
}
/**
* @brief Disable input mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable input mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable output mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
if (gpio_num < 32) {
hw->enable_w1tc = (0x1 << gpio_num);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->enable1_w1tc, data, (0x1 << (gpio_num - 32)));
}
// Ensure no other output signal is routed via GPIO matrix to this pin
REG_WRITE(GPIO_FUNC0_OUT_SEL_CFG_REG + (gpio_num * 4),
SIG_GPIO_OUT_IDX);
}
/**
* @brief Enable output mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
if (gpio_num < 32) {
hw->enable_w1ts = (0x1 << gpio_num);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->enable1_w1ts, data, (0x1 << (gpio_num - 32)));
}
}
/**
* @brief Disable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable open-drain mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_od_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
hw->pin[gpio_num].pad_driver = 0;
}
/**
* @brief Enable open-drain mode on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
hw->pin[gpio_num].pad_driver = 1;
}
/**
* @brief GPIO set output level
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param level Output level. 0: low ; 1: high
*/
static inline void gpio_ll_set_level(gpio_dev_t *hw, gpio_num_t gpio_num, uint32_t level)
{
if (level) {
if (gpio_num < 32) {
hw->out_w1ts = (1 << gpio_num);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->out1_w1ts, data, (1 << (gpio_num - 32)));
}
} else {
if (gpio_num < 32) {
hw->out_w1tc = (1 << gpio_num);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->out1_w1tc, data, (1 << (gpio_num - 32)));
}
}
}
/**
* @brief GPIO get input level
*
* @warning If the pad is not configured for input (or input and output) the returned value is always 0.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
*
* @return
* - 0 the GPIO input level is 0
* - 1 the GPIO input level is 1
*/
static inline int gpio_ll_get_level(gpio_dev_t *hw, gpio_num_t gpio_num)
{
if (gpio_num < 32) {
return (hw->in >> gpio_num) & 0x1;
} else {
return (HAL_FORCE_READ_U32_REG_FIELD(hw->in1, data) >> (gpio_num - 32)) & 0x1;
}
}
/**
* @brief Enable GPIO wake-up function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number.
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
*/
static inline void gpio_ll_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
hw->pin[gpio_num].int_type = intr_type;
hw->pin[gpio_num].wakeup_enable = 0x1;
}
/**
* @brief Disable GPIO wake-up function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
hw->pin[gpio_num].wakeup_enable = 0;
}
/**
* @brief Set GPIO pad drive capability
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Drive capability of the pad
*/
static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t strength)
{
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, strength, FUN_DRV_S);
}
/**
* @brief Get GPIO pad drive capability
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Pointer to accept drive capability of the pad
*/
static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t *strength)
{
*strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, FUN_DRV_S);
}
/**
* @brief Enable all digital gpio pad hold function during Deep-sleep.
*
* @param hw Peripheral GPIO hardware instance address.
*/
static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw)
{
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M);
}
/**
* @brief Disable all digital gpio pad hold function during Deep-sleep.
*
* @param hw Peripheral GPIO hardware instance address.
*/
static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M);
}
/**
* @brief Enable gpio pad hold function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
*/
static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
}
/**
* @brief Disable gpio pad hold function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
*/
static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
}
/**
* @brief Set pad input to a peripheral signal through the IOMUX.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
}
/**
* @brief Select a function for the pin in the IOMUX
*
* @param pin_name Pin name to configure
* @param func Function to assign to the pin
*/
static inline __attribute__((always_inline)) void gpio_ll_iomux_func_sel(uint32_t pin_name, uint32_t func)
{
PIN_FUNC_SELECT(pin_name, func);
}
/**
* @brief Set peripheral output to an GPIO pad through the IOMUX.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num gpio_num GPIO number of the pad.
* @param func The function number of the peripheral pin to output pin.
* One of the ``FUNC_X_*`` of specified pin (X) in ``soc/io_mux_reg.h``.
* @param oen_inv True if the output enable needs to be inverted, otherwise False.
*/
static inline void gpio_ll_iomux_out(gpio_dev_t *hw, uint8_t gpio_num, int func, uint32_t oen_inv)
{
hw->func_out_sel_cfg[gpio_num].oen_sel = 0;
hw->func_out_sel_cfg[gpio_num].oen_inv_sel = oen_inv;
gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[gpio_num], func);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,928 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for I2C register operations
#pragma once
#include "hal/misc.h"
#include "soc/i2c_periph.h"
#include "soc/i2c_struct.h"
#include "hal/i2c_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */
/**
* @brief I2C hardware cmd register fields.
*/
typedef union {
struct {
uint32_t byte_num: 8,
ack_en: 1,
ack_exp: 1,
ack_val: 1,
op_code: 3,
reserved14: 17,
done: 1;
};
uint32_t val;
} i2c_hw_cmd_t;
/**
* @brief I2C interrupt event
*/
typedef enum {
I2C_INTR_EVENT_ERR,
I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */
I2C_INTR_EVENT_NACK, /*!< I2C NACK event */
I2C_INTR_EVENT_TOUT, /*!< I2C time out event */
I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */
I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */
I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */
I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */
} i2c_intr_event_t;
/**
* @brief Data structure for calculating I2C bus timing.
*/
typedef struct {
uint16_t scl_low; /*!< I2C scl low period */
uint16_t scl_high; /*!< I2C scl hight period */
uint16_t sda_hold; /*!< I2C scl low period */
uint16_t sda_sample; /*!< I2C sda sample time */
uint16_t setup; /*!< I2C start and stop condition setup period */
uint16_t hold; /*!< I2C start and stop condition hold period */
uint16_t tout; /*!< I2C bus timeout period */
} i2c_clk_cal_t;
// I2C operation mode command
#define I2C_LL_CMD_RESTART 0 /*!<I2C restart command */
#define I2C_LL_CMD_WRITE 1 /*!<I2C write command */
#define I2C_LL_CMD_READ 2 /*!<I2C read command */
#define I2C_LL_CMD_STOP 3 /*!<I2C stop command */
#define I2C_LL_CMD_END 4 /*!<I2C end command */
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
// Get the I2C hardware FIFO address
#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num))
// I2C master TX interrupt bitmap
#define I2C_LL_MASTER_TX_INT (I2C_ACK_ERR_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)
// I2C master RX interrupt bitmap
#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
// I2C slave TX interrupt bitmap
#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_EMPTY_INT_ENA_M)
// I2C slave RX interrupt bitmap
#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M)
// I2C source clock frequency
#define I2C_LL_CLK_SRC_FREQ(src_clk) (80*1000*1000)
// I2C max timeout value
#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V
/**
* @brief Calculate I2C bus frequency
*
* @param source_clk I2C source clock
* @param bus_freq I2C bus frequency
* @param clk_cal Pointer to accept the clock configuration
*
* @return None
*/
static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal)
{
uint32_t half_cycle = source_clk / bus_freq / 2;
clk_cal->scl_low = half_cycle;
clk_cal->scl_high = half_cycle;
clk_cal->sda_hold = half_cycle / 2;
clk_cal->sda_sample = clk_cal->scl_high / 2;
clk_cal->setup = half_cycle;
clk_cal->hold = half_cycle;
clk_cal->tout = half_cycle * 20; //default we set the timeout value to 10 bus cycles.
}
/**
* @brief Configure the I2C bus timing related register.
*
* @param hw Beginning address of the peripheral registers
* @param bus_cfg Pointer to the data structure holding the register configuration.
*
* @return None
*/
static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg)
{
/* SCL period. According to the TRM, we should always subtract 1 to SCL low period */
assert(bus_cfg->scl_low > 0);
hw->scl_low_period.period = bus_cfg->scl_low - 1;
/* Still according to the TRM, if filter is not enbled, we have to subtract 7,
* if SCL filter is enabled, we have to subtract:
* 8 if SCL filter is between 0 and 2 (included)
* 6 + SCL threshold if SCL filter is between 3 and 7 (included)
* to SCL high period */
uint16_t scl_high = bus_cfg->scl_high;
/* In the "worst" case, we will subtract 13, make sure the result will still be correct */
assert(scl_high > 13);
if (hw->scl_filter_cfg.en) {
if (hw->scl_filter_cfg.thres <= 2) {
scl_high -= 8;
} else {
assert(hw->scl_filter_cfg.thres <= 7);
scl_high -= hw->scl_filter_cfg.thres + 6;
}
} else {
scl_high -= 7;
}
hw->scl_high_period.period = scl_high;
//sda sample
hw->sda_hold.time = bus_cfg->sda_hold;
hw->sda_sample.time = bus_cfg->sda_sample;
//setup
hw->scl_rstart_setup.time = bus_cfg->setup;
hw->scl_stop_setup.time = bus_cfg->setup;
//hold
hw->scl_start_hold.time = bus_cfg->hold;
hw->scl_stop_hold.time = bus_cfg->hold;
hw->timeout.tout = bus_cfg->tout;
}
/**
* @brief Reset I2C txFIFO
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_txfifo_rst(i2c_dev_t *hw)
{
hw->fifo_conf.tx_fifo_rst = 1;
hw->fifo_conf.tx_fifo_rst = 0;
}
/**
* @brief Reset I2C rxFIFO
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw)
{
hw->fifo_conf.rx_fifo_rst = 1;
hw->fifo_conf.rx_fifo_rst = 0;
}
/**
* @brief Configure I2C SCL timing
*
* @param hw Beginning address of the peripheral registers
* @param hight_period The I2C SCL hight period (in APB cycle)
* @param low_period The I2C SCL low period (in APB cycle)
*
* @return None.
*/
static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int low_period)
{
hw->scl_low_period.period = low_period;
hw->scl_high_period.period = hight_period;
}
/**
* @brief Clear I2C interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be cleared
*
* @return None
*/
static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_clr.val = mask;
}
/**
* @brief Enable I2C interrupt
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be enabled
*
* @return None
*/
static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_ena.val |= mask;
}
/**
* @brief Disable I2C interrupt
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be disabled
*
* @return None
*/
static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_ena.val &= (~mask);
}
/**
* @brief Get I2C interrupt status
*
* @param hw Beginning address of the peripheral registers
*
* @return I2C interrupt status
*/
static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw)
{
return hw->int_status.val;
}
/**
* @brief Configure I2C memory access mode, FIFO mode or non-FIFO mode
*
* @param hw Beginning address of the peripheral registers
* @param fifo_mode_en Set true to enable FIFO access mode, else, set it false
*
* @return None
*/
static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en)
{
hw->fifo_conf.nonfifo_en = fifo_mode_en ? 0 : 1;
}
/**
* @brief Configure I2C timeout
*
* @param hw Beginning address of the peripheral registers
* @param tout_num The I2C timeout value needs to be set (in APB cycle)
*
* @return None
*/
static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout)
{
hw->timeout.tout = tout;
}
/**
* @brief Configure I2C slave address
*
* @param hw Beginning address of the peripheral registers
* @param slave_addr I2C slave address needs to be set
* @param addr_10bit_en Set true to enable 10-bit slave address mode, set false to enable 7-bit address mode
*
* @return None
*/
static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, bool addr_10bit_en)
{
hw->slave_addr.addr = slave_addr;
hw->slave_addr.en_10bit = addr_10bit_en;
}
/**
* @brief Write I2C hardware command register
*
* @param hw Beginning address of the peripheral registers
* @param cmd I2C hardware command
* @param cmd_idx The index of the command register, should be less than 16
*
* @return None
*/
static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd_idx)
{
hw->command[cmd_idx].val = cmd.val;
}
/**
* @brief Configure I2C start timing
*
* @param hw Beginning address of the peripheral registers
* @param start_setup The start condition setup period (in APB cycle)
* @param start_hold The start condition hold period (in APB cycle)
*
* @return None
*/
static inline void i2c_ll_set_start_timing(i2c_dev_t *hw, int start_setup, int start_hold)
{
hw->scl_rstart_setup.time = start_setup;
hw->scl_start_hold.time = start_hold;
}
/**
* @brief Configure I2C stop timing
*
* @param hw Beginning address of the peripheral registers
* @param stop_setup The stop condition setup period (in APB cycle)
* @param stop_hold The stop condition hold period (in APB cycle)
*
* @return None
*/
static inline void i2c_ll_set_stop_timing(i2c_dev_t *hw, int stop_setup, int stop_hold)
{
hw->scl_stop_setup.time = stop_setup;
hw->scl_stop_hold.time = stop_hold;
}
/**
* @brief Configure I2C stop timing
*
* @param hw Beginning address of the peripheral registers
* @param sda_sample The SDA sample time (in APB cycle)
* @param sda_hold The SDA hold time (in APB cycle)
*
* @return None
*/
static inline void i2c_ll_set_sda_timing(i2c_dev_t *hw, int sda_sample, int sda_hold)
{
hw->sda_hold.time = sda_hold;
hw->sda_sample.time = sda_sample;
}
/**
* @brief Set I2C txFIFO empty threshold
*
* @param hw Beginning address of the peripheral registers
* @param empty_thr The txFIFO empty threshold
*
* @return None
*/
static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
{
hw->fifo_conf.tx_fifo_empty_thrhd = empty_thr;
}
/**
* @brief Set I2C rxFIFO full threshold
*
* @param hw Beginning address of the peripheral registers
* @param full_thr The rxFIFO full threshold
*
* @return None
*/
static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
{
hw->fifo_conf.rx_fifo_full_thrhd = full_thr;
}
/**
* @brief Set the I2C data mode, LSB or MSB
*
* @param hw Beginning address of the peripheral registers
* @param tx_mode Tx data bit mode
* @param rx_mode Rx data bit mode
*
* @return None
*/
static inline void i2c_ll_set_data_mode(i2c_dev_t *hw, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode)
{
hw->ctr.tx_lsb_first = tx_mode;
hw->ctr.rx_lsb_first = rx_mode;
}
/**
* @brief Get the I2C data mode
*
* @param hw Beginning address of the peripheral registers
* @param tx_mode Pointer to accept the received bytes mode
* @param rx_mode Pointer to accept the sended bytes mode
*
* @return None
*/
static inline void i2c_ll_get_data_mode(i2c_dev_t *hw, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode)
{
*tx_mode = hw->ctr.tx_lsb_first;
*rx_mode = hw->ctr.rx_lsb_first;
}
/**
* @brief Get I2C sda timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param sda_sample Pointer to accept the SDA sample timing configuration
* @param sda_hold Pointer to accept the SDA hold timing configuration
*
* @return None
*/
static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sda_hold)
{
*sda_hold = hw->sda_hold.time;
*sda_sample = hw->sda_sample.time;
}
/**
* @brief Get the I2C hardware version
*
* @param hw Beginning address of the peripheral registers
*
* @return The I2C hardware version
*/
static inline uint32_t i2c_ll_get_hw_version(i2c_dev_t *hw)
{
return hw->date;
}
/**
* @brief Check if the I2C bus is busy
*
* @param hw Beginning address of the peripheral registers
*
* @return True if I2C state machine is busy, else false will be returned
*/
static inline bool i2c_ll_is_bus_busy(i2c_dev_t *hw)
{
return hw->status_reg.bus_busy;
}
/**
* @brief Check if I2C is master mode
*
* @param hw Beginning address of the peripheral registers
*
* @return True if I2C is master mode, else false will be returned
*/
static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw)
{
return hw->ctr.ms_mode;
}
/**
* @brief Get the rxFIFO readable length
*
* @param hw Beginning address of the peripheral registers
*
* @return RxFIFO readable length
*/
static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw)
{
return hw->status_reg.rx_fifo_cnt;
}
/**
* @brief Get I2C txFIFO writable length
*
* @param hw Beginning address of the peripheral registers
*
* @return TxFIFO writable length
*/
static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw)
{
return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt;
}
/**
* @brief Get I2C timeout configuration
*
* @param hw Beginning address of the peripheral registers
*
* @return The I2C timeout value
*/
static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw)
{
return hw->timeout.tout;
}
/**
* @brief Start I2C transfer
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_trans_start(i2c_dev_t *hw)
{
hw->ctr.trans_start = 1;
}
/**
* @brief Get I2C start timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param setup_time Pointer to accept the start condition setup period
* @param hold_time Pointer to accept the start condition hold period
*
* @return None
*/
static inline void i2c_ll_get_start_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
{
*setup_time = hw->scl_rstart_setup.time;
*hold_time = hw->scl_start_hold.time;
}
/**
* @brief Get I2C stop timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param setup_time Pointer to accept the stop condition setup period
* @param hold_time Pointer to accept the stop condition hold period
*
* @return None
*/
static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
{
*setup_time = hw->scl_stop_setup.time;
*hold_time = hw->scl_stop_hold.time;
}
/**
* @brief Get I2C SCL timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param high_period Pointer to accept the SCL high period
* @param low_period Pointer to accept the SCL low period
*
* @return None
*/
static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *low_period)
{
*high_period = hw->scl_high_period.period;
*low_period = hw->scl_low_period.period;
}
/**
* @brief Write the I2C hardware txFIFO
*
* @param hw Beginning address of the peripheral registers
* @param ptr Pointer to data buffer
* @param len Amount of data needs to be writen
*
* @return None.
*/
static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
{
uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c;
for(int i = 0; i < len; i++) {
WRITE_PERI_REG(fifo_addr, ptr[i]);
}
}
/**
* @brief Read the I2C hardware rxFIFO
*
* @param hw Beginning address of the peripheral registers
* @param ptr Pointer to data buffer
* @param len Amount of data needs read
*
* @return None
*/
static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
{
for(int i = 0; i < len; i++) {
ptr[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->fifo_data, data);
}
}
/**
* @brief Configure I2C hardware filter
*
* @param hw Beginning address of the peripheral registers
* @param filter_num If the glitch period on the line is less than this value, it can be filtered out
* If `filter_num == 0`, the filter will be disabled
*
* @return None
*/
static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num)
{
if(filter_num > 0) {
hw->scl_filter_cfg.thres = filter_num;
hw->sda_filter_cfg.thres = filter_num;
hw->scl_filter_cfg.en = 1;
hw->sda_filter_cfg.en = 1;
} else {
hw->scl_filter_cfg.en = 0;
hw->sda_filter_cfg.en = 0;
}
}
/**
* @brief Get I2C hardware filter configuration
*
* @param hw Beginning address of the peripheral registers
*
* @return The hardware filter configuration
*/
static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw)
{
return hw->sda_filter_cfg.thres;
}
/**
* @brief Enable I2C master TX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw)
{
hw->int_clr.val = ~0;
hw->int_ena.val = I2C_LL_MASTER_TX_INT;
}
/**
* @brief Enable I2C master RX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw)
{
hw->int_clr.val = ~0;
hw->int_ena.val = I2C_LL_MASTER_RX_INT;
}
/**
* @brief Disable I2C master TX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw)
{
hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT);
}
/**
* @brief Disable I2C master RX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw)
{
hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT);
}
/**
* @brief Clear I2C master TX interrupt status register
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw)
{
hw->int_clr.val = I2C_LL_MASTER_TX_INT;
}
/**
* @brief Clear I2C master RX interrupt status register
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw)
{
hw->int_clr.val = I2C_LL_MASTER_RX_INT;
}
/**
* @brief
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw)
{
hw->int_ena.val |= I2C_LL_SLAVE_TX_INT;
}
/**
* @brief Enable I2C slave RX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw)
{
hw->int_ena.val |= I2C_LL_SLAVE_RX_INT;
}
/**
* @brief Disable I2C slave TX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw)
{
hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT);
}
/**
* @brief Disable I2C slave RX interrupt
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw)
{
hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT);
}
/**
* @brief Clear I2C slave TX interrupt status register
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw)
{
hw->int_clr.val = I2C_LL_SLAVE_TX_INT;
}
/**
* @brief Clear I2C slave RX interrupt status register.
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw)
{
hw->int_clr.val = I2C_LL_SLAVE_RX_INT;
}
/**
* @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw)
{
;//ESP32 do not support
}
/**
* @brief Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling the bus low,
* master can controls the SCL bus to generate 9 CLKs.
*
* Note: The master cannot detect if deadlock happens, but when the scl_st_to interrupt is generated, a deadlock may occur.
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw)
{
;//ESP32 do not support
}
/**
* @brief Set I2C source clock
*
* @param hw Beginning address of the peripheral registers
* @param src_clk Source clock of the I2C
*
* @return None
*/
static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_sclk_t src_clk)
{
;//Not support on ESP32
}
/**
* @brief Get I2C master interrupt event
*
* @param hw Beginning address of the peripheral registers
* @param event Pointer to accept the interrupt event
*
* @return None
*/
static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
{
typeof(hw->int_status) int_sts = hw->int_status;
if (int_sts.arbitration_lost) {
*event = I2C_INTR_EVENT_ARBIT_LOST;
} else if (int_sts.ack_err) {
*event = I2C_INTR_EVENT_NACK;
} else if (int_sts.time_out) {
*event = I2C_INTR_EVENT_TOUT;
} else if (int_sts.end_detect) {
*event = I2C_INTR_EVENT_END_DET;
} else if (int_sts.trans_complete) {
*event = I2C_INTR_EVENT_TRANS_DONE;
} else {
*event = I2C_INTR_EVENT_ERR;
}
}
/**
* @brief Get I2C slave interrupt event
*
* @param hw Beginning address of the peripheral registers
* @param event Pointer to accept the interrupt event
*
* @return None
*/
static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
{
typeof(hw->int_status) int_sts = hw->int_status;
if (int_sts.tx_fifo_empty) {
*event = I2C_INTR_EVENT_TXFIFO_EMPTY;
} else if (int_sts.trans_complete) {
*event = I2C_INTR_EVENT_TRANS_DONE;
} else if (int_sts.rx_fifo_full) {
*event = I2C_INTR_EVENT_RXFIFO_FULL;
} else {
*event = I2C_INTR_EVENT_ERR;
}
}
/**
* @brief Init I2C master
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_init(i2c_dev_t *hw)
{
typeof(hw->ctr) ctrl_reg;
ctrl_reg.val = 0;
ctrl_reg.ms_mode = 1;
ctrl_reg.sda_force_out = 1;
ctrl_reg.scl_force_out = 1;
hw->ctr.val = ctrl_reg.val;
}
/**
* @brief Init I2C slave
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_slave_init(i2c_dev_t *hw)
{
typeof(hw->ctr) ctrl_reg;
ctrl_reg.val = 0;
ctrl_reg.sda_force_out = 1;
ctrl_reg.scl_force_out = 1;
hw->ctr.val = ctrl_reg.val;
hw->fifo_conf.fifo_addr_cfg_en = 0;
}
/**
* @brief Update I2C configuration
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_update(i2c_dev_t *hw)
{
;// ESP32 do not support
}
/**
* @brief Configure I2C SCL timing
*
* @param hw Beginning address of the peripheral registers
* @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2)
* @param low_period The I2C SCL low period (in core clock cycle, low_period > 1)
* @param wait_high_period The I2C SCL wait rising edge period.
*
* @return None.
*/
static inline void i2c_ll_set_scl_clk_timing(i2c_dev_t *hw, int high_period, int low_period, int wait_high_period)
{
(void)wait_high_period;
hw->scl_low_period.period = low_period;
hw->scl_high_period.period = high_period;
}
/**
* @brief Get I2C SCL timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param high_period Pointer to accept the SCL high period
* @param low_period Pointer to accept the SCL low period
*
* @return None
*/
static inline void i2c_ll_get_scl_clk_timing(i2c_dev_t *hw, int *high_period, int *low_period, int *wait_high_period)
{
*wait_high_period = 0; // Useless
*high_period = hw->scl_high_period.period;
*low_period = hw->scl_low_period.period;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,949 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 I2S register operations
#pragma once
#include <stdbool.h>
#include "hal/misc.h"
#include "soc/i2s_periph.h"
#include "soc/i2s_struct.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : (((num) == 1) ? (&I2S1) : NULL))
#define I2S_LL_AD_BCK_FACTOR (2)
#define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_BASE_CLK (2 * APB_CLK_FREQ)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (6)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
#define I2S_LL_EVENT_TX_EOF (1 << 12)
#define I2S_LL_BCK_MAX_PRESCALE (64)
/* I2S clock configuration structure */
typedef struct {
uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a)
uint16_t a;
uint16_t b; // The decimal part of module clock devider, the decimal is: b/a
} i2s_ll_mclk_div_t;
/**
* @brief Enable DMA descriptor owner check
*
* @param hw Peripheral I2S hardware instance address.
* @param en whether to enable owner check
*/
static inline void i2s_ll_dma_enable_owner_check(i2s_dev_t *hw, bool en)
{
hw->lc_conf.check_owner = en;
}
/**
* @brief Enable DMA descriptor write back
*
* @param hw Peripheral I2S hardware instance address.
* @param en whether to enable write back
*/
static inline void i2s_ll_dma_enable_auto_write_back(i2s_dev_t *hw, bool en)
{
hw->lc_conf.out_auto_wrback = en;
}
/**
* @brief I2S DMA generate EOF event on data in FIFO poped out
*
* @param hw Peripheral I2S hardware instance address.
* @param en True to enable, False to disable
*/
static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
{
hw->lc_conf.out_eof_mode = en;
}
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
}
}
/**
* @brief I2S module disable clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
{
if (hw->clkm_conf.clk_en == 1) {
hw->clkm_conf.clk_en = 0;
}
}
/**
* @brief I2S tx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx msb right
*/
static inline void i2s_ll_tx_enable_msb_right(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_msb_right = enable;
}
/**
* @brief I2S rx msb right enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx msb right
*/
static inline void i2s_ll_rx_enable_msb_right(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_msb_right = enable;
}
/**
* @brief I2S tx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable send right channel first
*/
static inline void i2s_ll_tx_enable_right_first(i2s_dev_t *hw, bool enable)
{
hw->conf.tx_right_first = enable;
}
/**
* @brief I2S rx right channel first
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable receive right channel first
*/
static inline void i2s_ll_rx_enable_right_first(i2s_dev_t *hw, bool enable)
{
hw->conf.rx_right_first = enable;
}
/**
* @brief I2S tx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable tx fifo module
*/
static inline void i2s_ll_tx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.tx_fifo_mod_force_en = enable;
}
/**
* @brief I2S rx fifo module force enable
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable rx fifo module
*/
static inline void i2s_ll_rx_force_enable_fifo_mod(i2s_dev_t *hw, bool enable)
{
hw->fifo_conf.rx_fifo_mod_force_en = enable;
}
/**
* @brief Enable I2S TX slave mode
*
* @param hw Peripheral I2S hardware instance address.
* @param slave_en Set true to enable slave mode
*/
static inline void i2s_ll_tx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
{
hw->conf.tx_slave_mod = slave_en;
}
/**
* @brief Enable I2S RX slave mode
*
* @param hw Peripheral I2S hardware instance address.
* @param slave_en Set true to enable slave mode
*/
static inline void i2s_ll_rx_set_slave_mod(i2s_dev_t *hw, bool slave_en)
{
hw->conf.rx_slave_mod = slave_en;
}
/**
* @brief Reset I2S TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_reset(i2s_dev_t *hw)
{
hw->conf.tx_reset = 1;
hw->conf.tx_reset = 0;
}
/**
* @brief Reset I2S RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_reset(i2s_dev_t *hw)
{
hw->conf.rx_reset = 1;
hw->conf.rx_reset = 0;
}
/**
* @brief Reset I2S TX FIFO
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_reset_fifo(i2s_dev_t *hw)
{
hw->conf.tx_fifo_reset = 1;
hw->conf.tx_fifo_reset = 0;
}
/**
* @brief Reset I2S RX FIFO
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
{
hw->conf.rx_fifo_reset = 1;
hw->conf.rx_fifo_reset = 0;
}
/**
* @brief Set TX source clock
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock
*/
static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
//0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock
//1: Enable APLL clock, I2S module will using APLL as source clock
hw->clkm_conf.clka_en = (src == I2S_CLK_APLL) ? 1 : 0;
}
/**
* @brief Set RX source clock
*
* @param hw Peripheral I2S hardware instance address.
* @param src I2S source clock
*/
static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
{
//0: disable APLL clock, I2S module will using PLL_D2_CLK(160M) as source clock
//1: Enable APLL clock, I2S module will using APLL as source clock
hw->clkm_conf.clka_en = (src == I2S_CLK_APLL) ? 1 : 0;
}
/**
* @brief Set I2S tx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bck div num
*/
static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bck_div_num = val;
}
/**
* @brief Configure I2S TX clock devider
*
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div);
hw->clkm_conf.clkm_div_b = set->b;
hw->clkm_conf.clkm_div_a = set->a;
}
/**
* @brief Set I2S rx bck div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bck div num
*/
static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.rx_bck_div_num = val;
}
/**
* @brief Configure I2S RX clock devider
*
* @param hw Peripheral I2S hardware instance address.
* @param set Pointer to I2S clock devider configuration paramater
*/
static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div);
hw->clkm_conf.clkm_div_b = set->b;
hw->clkm_conf.clkm_div_a = set->a;
}
/**
* @brief Enable interrupt by mask
*
* @param hw Peripheral I2S hardware instance address.
* @param mask Interrupt event mask
* @param en true to enable, false to disable
*/
static inline void i2s_ll_enable_intr(i2s_dev_t *hw, uint32_t mask, bool en)
{
if (en) {
hw->int_ena.val |= mask;
} else {
hw->int_ena.val &= ~mask;
}
}
/**
* @brief Enable TX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_enable_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 1;
hw->int_ena.out_dscr_err = 1;
}
/**
* @brief Disable TX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_disable_intr(i2s_dev_t *hw)
{
hw->int_ena.out_eof = 0;
hw->int_ena.out_dscr_err = 0;
}
/**
* @brief Enable RX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_enable_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 1;
hw->int_ena.in_dscr_err = 1;
}
/**
* @brief Disable RX interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_disable_intr(i2s_dev_t *hw)
{
hw->int_ena.in_suc_eof = 0;
hw->int_ena.in_dscr_err = 0;
}
/**
* @brief Get interrupt status register address
*
* @param hw Peripheral I2S hardware instance address.
* @return interrupt status register address
*/
static inline volatile void *i2s_ll_get_intr_status_reg(i2s_dev_t *hw)
{
return &hw->int_st;
}
/**
* @brief Get I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @return
* - module interrupt status
*/
static inline uint32_t i2s_ll_get_intr_status(i2s_dev_t *hw)
{
return hw->int_st.val;
}
/**
* @brief Clear I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param clr_mask Interrupt mask to clear interrupt status
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t clr_mask)
{
hw->int_clr.val = clr_mask;
}
/**
* @brief Reset dma out
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_reset_dma(i2s_dev_t *hw)
{
hw->lc_conf.out_rst = 1;
hw->lc_conf.out_rst = 0;
}
/**
* @brief Reset dma in
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_reset_dma(i2s_dev_t *hw)
{
hw->lc_conf.in_rst = 1;
hw->lc_conf.in_rst = 0;
}
/**
* @brief Start out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
{
hw->out_link.start = 1;
}
/**
* @brief Set I2S out link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set out link address
*/
static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
{
hw->out_link.addr = val;
}
/**
* @brief Start TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_start(i2s_dev_t *hw)
{
hw->conf.tx_start = 1;
}
/**
* @brief Start RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_start(i2s_dev_t *hw)
{
hw->conf.rx_start = 1;
}
/**
* @brief Configure TX DMA descriptor address and start TX DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param link_addr DMA descriptor link address.
*/
static inline void i2s_ll_tx_start_link(i2s_dev_t *hw, uint32_t link_addr)
{
i2s_ll_set_out_link_addr(hw, link_addr);
i2s_ll_start_out_link(hw);
}
/**
* @brief Configure RX DMA descriptor address and start RX DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param link_addr DMA descriptor link address.
*/
static inline void i2s_ll_rx_start_link(i2s_dev_t *hw, uint32_t link_addr)
{
hw->in_link.addr = link_addr;
hw->in_link.start = 1;
}
/**
* @brief Stop TX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_stop(i2s_dev_t *hw)
{
hw->conf.tx_start = 0;
}
/**
* @brief Stop RX module
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_stop(i2s_dev_t *hw)
{
hw->conf.rx_start = 0;
}
/**
* @brief Stop out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_tx_stop_link(i2s_dev_t *hw)
{
hw->out_link.stop = 1;
}
/**
* @brief Stop in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_rx_stop_link(i2s_dev_t *hw)
{
hw->in_link.stop = 1;
}
/**
* @brief Get I2S out eof descriptor address
*
* @param hw Peripheral I2S hardware instance address.
* @param eof_addr Pointer to accept out eof des address
*/
static inline void i2s_ll_tx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
{
*eof_addr = hw->out_eof_des_addr;
}
/**
* @brief Get I2S in eof descriptor address
*
* @param hw Peripheral I2S hardware instance address.
* @param eof_addr Pointer to accept in eof des address
*/
static inline void i2s_ll_rx_get_eof_des_addr(i2s_dev_t *hw, uint32_t *eof_addr)
{
*eof_addr = hw->in_eof_des_addr;
}
/**
* @brief Configure the received length to trigger in_suc_eof interrupt
*
* @param hw Peripheral I2S hardware instance address.
* @param eof_num the byte length to trigger in_suc_eof interrupt
*/
static inline void i2s_ll_rx_set_eof_num(i2s_dev_t *hw, int eof_num)
{
// On ESP32, the eof_num count in words.
hw->rx_eof_num = eof_num / 4;
}
/**
* @brief Set I2S tx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx bits mod
*/
static inline void i2s_ll_tx_set_bits_mod(i2s_dev_t *hw, uint32_t val)
{
hw->sample_rate_conf.tx_bits_mod = val;
}
/**
* @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
*
* @param hw Peripheral I2S hardware instance address.
* @param chan_bit The chan bit width
* @param data_bit The audio data bit width
*/
static inline void i2s_ll_tx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
{
hw->fifo_conf.tx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
hw->sample_rate_conf.tx_bits_mod = data_bit;
}
/**
* @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit
*
* @param hw Peripheral I2S hardware instance address.
* @param chan_bit The chan bit width
* @param data_bit The audio data bit width
*/
static inline void i2s_ll_rx_set_sample_bit(i2s_dev_t *hw, uint8_t chan_bit, int data_bit)
{
hw->fifo_conf.rx_fifo_mod = (chan_bit <= I2S_BITS_PER_SAMPLE_16BIT ? 0 : 2);
hw->sample_rate_conf.rx_bits_mod = data_bit;
}
/**
* @brief Set whether to continue I2S signal on bus when TX FIFO is empty
*
* @param hw Peripheral I2S hardware instance address.
* @param en whether to stop when tx fifo is empty
*/
static inline void i2s_ll_tx_stop_on_fifo_empty(i2s_dev_t *hw, bool en)
{
hw->conf1.tx_stop_en = en;
}
/**
* @brief Set whether to bypass the internal PCM module
*
* @param hw Peripheral I2S hardware instance address.
* @param bypass whether to bypass the PCM module
*/
static inline void i2s_ll_tx_bypass_pcm(i2s_dev_t *hw, bool bypass)
{
hw->conf1.tx_pcm_bypass = bypass;
}
/**
* @brief Enable I2S DMA
*
* @param hw Peripheral I2S hardware instance address.
* @param ena Set true to enable DMA
*/
static inline void i2s_ll_enable_dma(i2s_dev_t *hw, bool ena)
{
hw->fifo_conf.dscr_en = ena;
}
/**
* @brief Configure TX WS signal width
*
* @param hw Peripheral I2S hardware instance address.
* @param width WS width in BCK cycle
*/
static inline void i2s_ll_tx_set_ws_width(i2s_dev_t *hw, int width)
{
hw->conf.tx_short_sync = width == 1 ? 1 : 0;
}
/**
* @brief Configure RX WS signal width
*
* @param hw Peripheral I2S hardware instance address.
* @param width WS width in BCK cycle
*/
static inline void i2s_ll_rx_set_ws_width(i2s_dev_t *hw, int width)
{
hw->conf.rx_short_sync = width == 1 ? 1 : 0;
}
/**
* @brief Enable TX MSB shift, the data will be launch at the first BCK clock
*
* @param hw Peripheral I2S hardware instance address.
* @param msb_shift_enable Set true to enable MSB shift
*/
static inline void i2s_ll_tx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
{
hw->conf.tx_msb_shift = msb_shift_enable;
}
/**
* @brief Enable RX MSB shift, the data will be launch at the first BCK clock
*
* @param hw Peripheral I2S hardware instance address.
* @param msb_shift_enable Set true to enable MSB shift
*/
static inline void i2s_ll_rx_enable_msb_shift(i2s_dev_t *hw, bool msb_shift_enable)
{
hw->conf.rx_msb_shift = msb_shift_enable;
}
/**
* @brief Set I2S tx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx chan mode
*/
static inline void i2s_ll_tx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.tx_chan_mod = val;
}
/**
* @brief Set I2S rx chan mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx chan mode
*/
static inline void i2s_ll_rx_set_chan_mod(i2s_dev_t *hw, uint32_t val)
{
hw->conf_chan.rx_chan_mod = val;
}
/**
* @brief Enable TX mono mode
*
* @param hw Peripheral I2S hardware instance address.
* @param mono_ena Set true to enable mono mde.
*/
static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.tx_bits_mod;
hw->fifo_conf.tx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
}
/**
* @brief Enable RX mono mode
*
* @param hw Peripheral I2S hardware instance address.
* @param mono_ena Set true to enable mono mde.
*/
static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena)
{
int data_bit = hw->sample_rate_conf.rx_bits_mod;
hw->fifo_conf.rx_fifo_mod = data_bit <= I2S_BITS_PER_SAMPLE_16BIT ? mono_ena : 2 + mono_ena;
}
/**
* @brief Enable I2S loopback mode
*
* @param hw Peripheral I2S hardware instance address.
* @param loopback_en Set true to share BCK and WS signal for tx module and rx module.
*/
static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool loopback_en)
{
hw->conf.sig_loopback = loopback_en;
}
/******************************I2S PDM Configurations*************************************/
/**
* @brief Configure RX PDM downsample
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr PDM downsample configuration paramater
*/
static inline void i2s_ll_rx_set_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t dsr)
{
hw->pdm_conf.rx_sinc_dsr_16_en = dsr;
}
/**
* @brief Get RX PDM downsample configuration
*
* @param hw Peripheral I2S hardware instance address.
* @param dsr Pointer to accept PDM downsample configuration
*/
static inline void i2s_ll_rx_get_pdm_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr)
{
*dsr = hw->pdm_conf.rx_sinc_dsr_16_en;
}
/**
* @brief Enable I2S TX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_ena Set true to enable TX PDM mode
*/
static inline void i2s_ll_tx_enable_pdm(i2s_dev_t *hw, bool pdm_ena)
{
hw->pdm_conf.tx_pdm_en = pdm_ena;
hw->pdm_conf.pcm2pdm_conv_en = pdm_ena;
}
/**
* @brief Enable I2S RX PDM mode
*
* @param hw Peripheral I2S hardware instance address.
* @param pdm_ena Set true to enable RX PDM mode
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_ena)
{
hw->pdm_conf.rx_pdm_en = pdm_ena;
hw->pdm_conf.pdm2pcm_conv_en = pdm_ena;
}
/**
* @brief Set I2S TX PDM prescale
*
* @param hw Peripheral I2S hardware instance address.
* @param prescale I2S TX PDM prescale
*/
static inline void i2s_ll_tx_set_pdm_prescale(i2s_dev_t *hw, bool prescale)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->pdm_conf, tx_prescale, prescale);
}
/**
* @brief Set I2S TX PDM high pass filter scaling
*
* @param hw Peripheral I2S hardware instance address.
* @param sig_scale I2S TX PDM signal scaling before transmit to the filter
*/
static inline void i2s_ll_tx_set_pdm_hp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
{
hw->pdm_conf.tx_hp_in_shift = sig_scale;
}
/**
* @brief Set I2S TX PDM low pass filter scaling
*
* @param hw Peripheral I2S hardware instance address.
* @param sig_scale I2S TX PDM signal scaling before transmit to the filter
*/
static inline void i2s_ll_tx_set_pdm_lp_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
{
hw->pdm_conf.tx_lp_in_shift = sig_scale;
}
/**
* @brief Set I2S TX PDM sinc filter scaling
*
* @param hw Peripheral I2S hardware instance address.
* @param sig_scale I2S TX PDM signal scaling before transmit to the filter
*/
static inline void i2s_ll_tx_set_pdm_sinc_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
{
hw->pdm_conf.tx_sinc_in_shift = sig_scale;
}
/**
* @brief Set I2S TX PDM sigma-delta filter scaling
*
* @param hw Peripheral I2S hardware instance address.
* @param sig_scale I2S TX PDM signal scaling before transmit to the filter
*/
static inline void i2s_ll_tx_set_pdm_sd_scale(i2s_dev_t *hw, i2s_pdm_sig_scale_t sig_scale)
{
hw->pdm_conf.tx_sigmadelta_in_shift = sig_scale;
}
/**
* @brief Configure I2S TX PDM sample rate
* Fpdm = 64*Fpcm*fp/fs
*
* @param hw Peripheral I2S hardware instance address.
* @param fp The fp value of TX PDM filter module group0.
* @param fs The fs value of TX PDM filter module group0.
*/
static inline void i2s_ll_tx_set_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs)
{
hw->pdm_freq_conf.tx_pdm_fp = fp;
hw->pdm_freq_conf.tx_pdm_fs = fs;
hw->pdm_conf.tx_sinc_osr2 = fp / fs;
}
/**
* @brief Get I2S TX PDM fp configuration paramater
*
* @param hw Peripheral I2S hardware instance address.
* @return
* - fp configuration paramater
*/
static inline uint32_t i2s_ll_tx_get_pdm_fp(i2s_dev_t *hw)
{
return hw->pdm_freq_conf.tx_pdm_fp;
}
/**
* @brief Get I2S TX PDM fs configuration paramater
*
* @param hw Peripheral I2S hardware instance address.
* @return
* - fs configuration paramater
*/
static inline uint32_t i2s_ll_tx_get_pdm_fs(i2s_dev_t *hw)
{
return hw->pdm_freq_conf.tx_pdm_fs;
}
/****************************I2S ADC/DAC Configurations***********************************/
/**
* @brief Enable I2S LCD mode
* @note Have to enable LCD mode to use build in ADC/DAC
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable LCD mode.
*/
static inline void i2s_ll_enable_lcd(i2s_dev_t *hw, bool enable)
{
hw->conf2.lcd_en = enable;
}
/**
* @brief Enable I2S camera mode
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable camera mode.
*/
static inline void i2s_ll_enable_camera(i2s_dev_t *hw, bool enable)
{
hw->conf2.camera_en = enable;
}
/**
* @brief Enable I2S build in ADC mode
*
* @param hw Peripheral I2S hardware instance address.
* @param enable Set true to enable build in ADC
*/
static inline void i2s_ll_enable_builtin_adc(i2s_dev_t *hw, bool enable)
{
hw->conf2.lcd_en = enable;
hw->conf2.camera_en = 0;
hw->conf.rx_right_first = 0;
hw->conf.rx_msb_shift = 0;
hw->conf.rx_mono = 0;
hw->conf.rx_short_sync = 0;
hw->fifo_conf.rx_fifo_mod = enable;
hw->conf_chan.rx_chan_mod = enable;
}
/**
* @brief Enable I2S build in DAC mode
*
* @param hw Peripheral I2S hardware instance address.
* * @param enable Set true to enable build in DAC
*/
static inline void i2s_ll_enable_builtin_dac(i2s_dev_t *hw, bool enable)
{
hw->conf2.lcd_en = enable;
hw->conf2.camera_en = 0;
hw->conf.tx_right_first = enable;
hw->conf.tx_msb_shift = 0;
hw->conf.tx_short_sync = 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,108 @@
// 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.
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#include "soc/soc.h"
#include "xtensa/xtensa_api.h"
#include "xt_instr_macros.h"
#include "xtensa/config/specreg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief enable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be enabled
*/
static inline void intr_cntrl_ll_enable_interrupts(uint32_t mask)
{
xt_ints_on(mask);
}
/**
* @brief disable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be disabled
*/
static inline void intr_cntrl_ll_disable_interrupts(uint32_t mask)
{
xt_ints_off(mask);
}
/**
* @brief Read the current interrupt mask of the CPU running this code.
*
* @return The current interrupt bitmask.
*/
static inline uint32_t intr_cntrl_ll_read_interrupt_mask(void)
{
uint32_t int_mask;
RSR(INTENABLE, int_mask);
return int_mask;
}
/**
* @brief checks if given interrupt number has a valid handler
*
* @param intr interrupt number ranged from 0 to 31
* @param cpu cpu number ranged betweeen 0 to SOC_CPU_CORES_NUM - 1
* @return true for valid handler, false otherwise
*/
static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
{
return xt_int_has_handler(intr, cpu);
}
/**
* @brief sets interrupt handler and optional argument of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
* @param handler handler invoked when an interrupt occurs
* @param arg optional argument to pass to the handler
*/
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
{
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
}
/**
* @brief Gets argument passed to handler of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
*
* @return argument used by handler of passed interrupt number
*/
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
{
return xt_get_interrupt_handler_arg(intr);
}
/**
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
*
* @param intr interrupt number ranged from 0 to 31
*/
static inline void intr_cntrl_ll_edge_int_acknowledge(int intr)
{
xthal_set_intclear(1 << intr);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,480 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for LEDC register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#include "hal/ledc_types.h"
#include "soc/ledc_periph.h"
#include "soc/ledc_struct.h"
#define LEDC_LL_GET_HW() &LEDC
#define LEDC_LL_FRACTIONAL_BITS (8)
#define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1)
#define LEDC_LL_GLOBAL_CLOCKS { \
LEDC_SLOW_CLK_APB, \
LEDC_SLOW_CLK_RTC8M, \
}
#define LEDC_LL_TIMER_SPECIFIC_CLOCKS \
{\
{ \
.clk = LEDC_REF_TICK, \
.freq = LEDC_REF_CLK_HZ, \
} \
}
/* On ESP32, APB clock is a timer-specific clock only in fast clock mode */
#define LEDC_LL_IS_TIMER_SPECIFIC_CLOCK(SPEED, CLK) (\
((CLK) == LEDC_USE_REF_TICK) || \
((SPEED) == LEDC_HIGH_SPEED_MODE && (CLK) == LEDC_USE_APB_CLK) \
)
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_set_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t slow_clk_sel){
hw->conf.slow_clk_sel = slow_clk_sel;
}
/**
* @brief Get LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t *slow_clk_sel){
*slow_clk_sel = hw->conf.slow_clk_sel;
}
/**
* @brief Update LEDC low speed timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_ls_timer_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
}
/**
* @brief Reset LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_rst(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
}
/**
* @brief Pause LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_pause(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
}
/**
* @brief Resume LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_resume(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
}
/**
* @brief Set LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_set_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider){
hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider = clock_divider;
}
/**
* @brief Get LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *clock_divider){
*clock_divider = hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider;
}
/**
* @brief Set LEDC timer clock source
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @return None
*/
static inline void ledc_ll_set_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t clk_src){
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = (clk_src == LEDC_APB_CLK);
}
/**
* @brief Get LEDC timer clock source
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Pointer to accept the timer clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t *clk_src){
if (hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel) {
*clk_src = LEDC_APB_CLK;
} else {
*clk_src = LEDC_REF_TICK;
}
}
/**
* @brief Set LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t duty_resolution){
hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution = duty_resolution;
}
/**
* @brief Get LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
*
* @return None
*/
static inline void ledc_ll_get_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *duty_resolution){
*duty_resolution = hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution;
}
/**
* @brief Update channel configure when select low speed mode
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
hw->channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1;
}
/**
* @brief Get LEDC max duty
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param max_duty Pointer to accept the max duty
*
* @return None
*/
static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *max_duty){
int timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
*max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution));
}
/**
* @brief Set LEDC hpoint value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_set_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val){
hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
}
/**
* @brief Get LEDC hpoint value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_get_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *hpoint_val){
*hpoint_val = hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint;
}
/**
* @brief Set LEDC the integer part of duty value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_val){
hw->channel_group[speed_mode].channel[channel_num].duty.duty = duty_val << 4;
}
/**
* @brief Get LEDC duty value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val Pointer to accept the LEDC duty value
*
* @return None
*/
static inline void ledc_ll_get_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *duty_val){
*duty_val = (hw->channel_group[speed_mode].channel[channel_num].duty_rd.duty_read >> 4);
}
/**
* @brief Set LEDC duty change direction
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction LEDC duty change direction, increase or decrease
*
* @return None
*/
static inline void ledc_ll_set_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc = duty_direction;
}
/**
* @brief Get LEDC duty change direction
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction Pointer to accept the LEDC duty change direction, increase or decrease
*
* @return None
*/
static inline void ledc_ll_get_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t *duty_direction){
*duty_direction = hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc;
}
/**
* @brief Set the number of increased or decreased times
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_num The number of increased or decreased times
*
* @return None
*/
static inline void ledc_ll_set_duty_num(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_num){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_num = duty_num;
}
/**
* @brief Set the duty cycles of increase or decrease
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_cycle The duty cycles
*
* @return None
*/
static inline void ledc_ll_set_duty_cycle(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_cycle){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_cycle = duty_cycle;
}
/**
* @brief Set the step scale of increase or decrease
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_scale The step scale
*
* @return None
*/
static inline void ledc_ll_set_duty_scale(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_scale){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_scale = duty_scale;
}
/**
* @brief Set the output enable
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param sig_out_en The output enable status
*
* @return None
*/
static inline void ledc_ll_set_sig_out_en(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool sig_out_en){
hw->channel_group[speed_mode].channel[channel_num].conf0.sig_out_en = sig_out_en;
}
/**
* @brief Set the duty start
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_start The duty start
*
* @return None
*/
static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool duty_start){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = duty_start;
}
/**
* @brief Set output idle level
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param idle_level The output idle level
*
* @return None
*/
static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t idle_level){
hw->channel_group[speed_mode].channel[channel_num].conf0.idle_lv = idle_level & 0x1;
}
/**
* @brief Set fade end interrupt enable
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param fade_end_intr_en The fade end interrupt enable status
*
* @return None
*/
static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool fade_end_intr_en){
uint32_t value = hw->int_ena.val;
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
hw->int_ena.val = fade_end_intr_en ? (value | BIT(int_en_base + channel_num)) : (value & (~(BIT(int_en_base + channel_num))));
}
/**
* @brief Get fade end interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param intr_status The fade end interrupt status
*
* @return None
*/
static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, uint32_t *intr_status){
uint32_t value = hw->int_st.val;
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
*intr_status = (value >> int_en_base) & 0xff;
}
/**
* @brief Clear fade end interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_clear_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
hw->int_clr.val = BIT(int_en_base + channel_num);
}
/**
* @brief Set timer index of the specified channel
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_bind_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t timer_sel){
hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel = timer_sel;
}
/**
* @brief Get timer index of the specified channel
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel Pointer to accept the LEDC timer index
*
* @return None
*/
static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t *timer_sel){
*timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
// 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.
#include <stdint.h>
#include "soc/soc_caps.h"
#include "xt_instr_macros.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t mpu_ll_id_to_addr(unsigned id)
{
// vpn - id
// 0x00000000 = 0
// 0x20000000 = 1
// 0x40000000 = 2
// 0x60000000 = 3
// 0x80000000 = 4
// 0xa0000000 = 5
// 0xc0000000 = 6
// 0xe0000000 = 7
return id * SOC_MPU_MIN_REGION_SIZE;
}
static inline void mpu_ll_set_region_rw(uint32_t addr)
{
WDTLB(0x0, addr); // cached, no allocate
}
static inline void mpu_ll_set_region_rwx(uint32_t addr)
{
WDTLB(0x2, addr); // bypass cache
}
static inline void mpu_ll_set_region_x(uint32_t addr)
{
WITLB(0x3, addr); // cached
}
static inline void mpu_ll_set_region_illegal(uint32_t addr)
{
WITLB(0xF, addr);
WDTLB(0xF, addr);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,264 @@
// 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.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "hal/misc.h"
#include "soc/timer_periph.h"
#include "soc/timer_group_struct.h"
#include "hal/wdt_types.h"
#include "esp_attr.h"
//Type check wdt_stage_action_t
_Static_assert(WDT_STAGE_ACTION_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
//Type check wdt_reset_sig_length_t
_Static_assert(WDT_RESET_SIG_LENGTH_100ns == TIMG_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_200ns == TIMG_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_300ns == TIMG_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_400ns == TIMG_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_500ns == TIMG_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_800ns == TIMG_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == TIMG_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == TIMG_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
/**
* @brief Enable the MWDT
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_enable(timg_dev_t *hw)
{
hw->wdt_config0.en = 1;
}
/**
* @brief Disable the MWDT
*
* @param hw Start address of the peripheral registers.
* @note This function does not disable the flashboot mode. Therefore, given that
* the MWDT is disabled using this function, a timeout can still occur
* if the flashboot mode is simultaneously enabled.
*/
FORCE_INLINE_ATTR void mwdt_ll_disable(timg_dev_t *hw)
{
hw->wdt_config0.en = 0;
}
/**
* Check if the MWDT is enabled
*
* @param hw Start address of the peripheral registers.
* @return True if the MWDT is enabled, false otherwise
*/
FORCE_INLINE_ATTR bool mwdt_ll_check_if_enabled(timg_dev_t *hw)
{
return (hw->wdt_config0.en) ? true : false;
}
/**
* @brief Configure a particular stage of the MWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to configure
* @param timeout Number of timer ticks for the stage to timeout
* @param behavior What action to take when the stage times out
*/
FORCE_INLINE_ATTR void mwdt_ll_config_stage(timg_dev_t *hw, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = behavior;
hw->wdt_config2 = timeout;
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = behavior;
hw->wdt_config3 = timeout;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = behavior;
hw->wdt_config4 = timeout;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = behavior;
hw->wdt_config5 = timeout;
break;
default:
break;
}
}
/**
* @brief Disable a particular stage of the MWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to disable
*/
FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
break;
default:
break;
}
}
/**
* @brief Enable or disable MWDT edge interrupt
*
* @param hw Start address of the peripheral registers.
* @param enable Whether to enable edge interrupt
*/
FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable)
{
hw->wdt_config0.edge_int_en = (enable) ? 1 : 0;
}
/**
* @brief Enable or disable MWDT level interrupt
*
* @param hw Start address of the peripheral registers.
* @param enable Whether to enable level interrupt
*/
FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable)
{
hw->wdt_config0.level_int_en = (enable) ? 1 : 0;
}
/**
* @brief Set the length of the CPU reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of CPU reset signal
*/
FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.cpu_reset_length = length;
}
/**
* @brief Set the length of the system reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of system reset signal
*/
FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.sys_reset_length = length;
}
/**
* @brief Enable/Disable the MWDT flashboot mode.
*
* @param hw Beginning address of the peripheral registers.
* @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode.
*
* @note Flashboot mode is independent and can trigger a WDT timeout event if the
* WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled
* on flashboot, and should be disabled by software when flashbooting completes.
*/
FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable)
{
hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
}
/**
* @brief Set the clock prescaler of the MWDT
*
* @param hw Start address of the peripheral registers.
* @param prescaler Prescaler value between 1 to 65535
*/
FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wdt_config1, clk_prescale, prescaler);
}
/**
* @brief Feed the MWDT
*
* Resets the current timer count and current stage.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw)
{
hw->wdt_feed = 1;
}
/**
* @brief Enable write protection of the MWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw)
{
hw->wdt_wprotect = 0;
}
/**
* @brief Disable write protection of the MWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw)
{
hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE;
}
/**
* @brief Clear the MWDT interrupt status.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw)
{
hw->int_clr_timers.wdt = 1;
}
/**
* @brief Set the interrupt enable bit for the MWDT interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param enable Whether to enable the MWDT interrupt
*/
FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable)
{
hw->int_ena.wdt = (enable) ? 1 : 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,409 @@
// Copyright 2015-2021 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 PCNT register operations
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "soc/pcnt_struct.h"
#include "hal/pcnt_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL)
#define PCNT_LL_MAX_GLITCH_WIDTH 1023
typedef enum {
PCNT_LL_EVENT_THRES1,
PCNT_LL_EVENT_THRES0,
PCNT_LL_EVENT_LOW_LIMIT,
PCNT_LL_EVENT_HIGH_LIMIT,
PCNT_LL_EVENT_ZERO_CROSS,
PCNT_LL_EVENT_MAX
} pcnt_ll_event_id_t;
#define PCNT_LL_EVENT_MASK ((1 << PCNT_LL_EVENT_MAX) - 1)
/**
* @brief Set PCNT channel edge action
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pos_act Counter action when detecting positive edge
* @param neg_act Counter action when detecting negative edge
*/
static inline void pcnt_ll_set_edge_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_edge_action_t pos_act, pcnt_channel_edge_action_t neg_act)
{
if (channel == 0) {
hw->conf_unit[unit].conf0.ch0_pos_mode = pos_act;
hw->conf_unit[unit].conf0.ch0_neg_mode = neg_act;
} else {
hw->conf_unit[unit].conf0.ch1_pos_mode = pos_act;
hw->conf_unit[unit].conf0.ch1_neg_mode = neg_act;
}
}
/**
* @brief Set PCNT channel level action
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param high_act Counter action when control signal is high level
* @param low_act Counter action when control signal is low level
*/
static inline void pcnt_ll_set_level_action(pcnt_dev_t *hw, uint32_t unit, uint32_t channel, pcnt_channel_level_action_t high_act, pcnt_channel_level_action_t low_act)
{
if (channel == 0) {
hw->conf_unit[unit].conf0.ch0_hctrl_mode = high_act;
hw->conf_unit[unit].conf0.ch0_lctrl_mode = low_act;
} else {
hw->conf_unit[unit].conf0.ch1_hctrl_mode = high_act;
hw->conf_unit[unit].conf0.ch1_lctrl_mode = low_act;
}
}
/**
* @brief Get pulse counter value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit Pulse Counter unit number
* @return PCNT count value (a signed integer)
*/
static inline int pcnt_ll_get_count(pcnt_dev_t *hw, uint32_t unit)
{
typeof(hw->cnt_unit[unit]) cnt_reg = hw->cnt_unit[unit];
int16_t value = cnt_reg.cnt_val;
return value;
}
/**
* @brief Pause PCNT counter of PCNT unit
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
*/
static inline void pcnt_ll_stop_count(pcnt_dev_t *hw, uint32_t unit)
{
hw->ctrl.val |= 1 << (2 * unit + 1);
}
/**
* @brief Resume counting for PCNT counter
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number, select from uint32_t
*/
static inline void pcnt_ll_start_count(pcnt_dev_t *hw, uint32_t unit)
{
hw->ctrl.val &= ~(1 << (2 * unit + 1));
}
/**
* @brief Clear PCNT counter value to zero
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number, select from uint32_t
*/
static inline void pcnt_ll_clear_count(pcnt_dev_t *hw, uint32_t unit)
{
hw->ctrl.val |= 1 << (2 * unit);
hw->ctrl.val &= ~(1 << (2 * unit));
}
/**
* @brief Enable PCNT interrupt for PCNT unit
* @note Each PCNT unit has five watch point events that share the same interrupt bit.
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit_mask PCNT units mask
* @param enable True to enable interrupt, False to disable interrupt
*/
static inline void pcnt_ll_enable_intr(pcnt_dev_t *hw, uint32_t unit_mask, bool enable)
{
if (enable) {
hw->int_ena.val |= unit_mask;
} else {
hw->int_ena.val &= ~unit_mask;
}
}
/**
* @brief Get PCNT interrupt status
*
* @param hw Peripheral PCNT hardware instance address.
* @return Interrupt status word
*/
__attribute__((always_inline)) static inline uint32_t pcnt_ll_get_intr_status(pcnt_dev_t *hw)
{
return hw->int_st.val;
}
/**
* @brief Clear PCNT interrupt status
*
* @param hw Peripheral PCNT hardware instance address.
* @param status value to clear interrupt status
*/
__attribute__((always_inline)) static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status)
{
hw->int_clr.val = status;
}
/**
* @brief Enable PCNT high limit event
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param enable true to enable, false to disable
*/
static inline void pcnt_ll_enable_high_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
{
hw->conf_unit[unit].conf0.thr_h_lim_en = enable;
}
/**
* @brief Enable PCNT low limit event
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param enable true to enable, false to disable
*/
static inline void pcnt_ll_enable_low_limit_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
{
hw->conf_unit[unit].conf0.thr_l_lim_en = enable;
}
/**
* @brief Enable PCNT zero cross event
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param enable true to enable, false to disable
*/
static inline void pcnt_ll_enable_zero_cross_event(pcnt_dev_t *hw, uint32_t unit, bool enable)
{
hw->conf_unit[unit].conf0.thr_zero_en = enable;
}
/**
* @brief Enable PCNT threshold event
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param thres Threshold ID
* @param enable true to enable, false to disable
*/
static inline void pcnt_ll_enable_thres_event(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, bool enable)
{
if (thres == 0) {
hw->conf_unit[unit].conf0.thr_thres0_en = enable;
} else {
hw->conf_unit[unit].conf0.thr_thres1_en = enable;
}
}
/**
* @brief Disable all PCNT threshold events
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit unit number
*/
static inline void pcnt_ll_disable_all_events(pcnt_dev_t *hw, uint32_t unit)
{
hw->conf_unit[unit].conf0.val &= ~(PCNT_LL_EVENT_MASK << 11);
}
/**
* @brief Set PCNT high limit value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param value PCNT high limit value
*/
static inline void pcnt_ll_set_high_limit_value(pcnt_dev_t *hw, uint32_t unit, int value)
{
typeof(hw->conf_unit[unit].conf2) conf2_reg = hw->conf_unit[unit].conf2;
conf2_reg.cnt_h_lim = value;
hw->conf_unit[unit].conf2 = conf2_reg;
}
/**
* @brief Set PCNT low limit value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param value PCNT low limit value
*/
static inline void pcnt_ll_set_low_limit_value(pcnt_dev_t *hw, uint32_t unit, int value)
{
typeof(hw->conf_unit[unit].conf2) conf2_reg = hw->conf_unit[unit].conf2;
conf2_reg.cnt_l_lim = value;
hw->conf_unit[unit].conf2 = conf2_reg;
}
/**
* @brief Set PCNT threshold value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param thres Threshold ID
* @param value PCNT threshold value
*/
static inline void pcnt_ll_set_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres, int value)
{
typeof(hw->conf_unit[unit].conf1) conf1_reg = hw->conf_unit[unit].conf1;
if (thres == 0) {
conf1_reg.cnt_thres0 = value;
} else {
conf1_reg.cnt_thres1 = value;
}
hw->conf_unit[unit].conf1 = conf1_reg;
}
/**
* @brief Get PCNT high limit value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return PCNT high limit value
*/
static inline int pcnt_ll_get_high_limit_value(pcnt_dev_t *hw, uint32_t unit)
{
typeof(hw->conf_unit[unit].conf2) conf2_reg = hw->conf_unit[unit].conf2;
int16_t value = conf2_reg.cnt_h_lim;
return value;
}
/**
* @brief Get PCNT low limit value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return PCNT high limit value
*/
static inline int pcnt_ll_get_low_limit_value(pcnt_dev_t *hw, uint32_t unit)
{
typeof(hw->conf_unit[unit].conf2) conf2_reg = hw->conf_unit[unit].conf2;
int16_t value = conf2_reg.cnt_l_lim;
return value;
}
/**
* @brief Get PCNT threshold value
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param thres Threshold ID
* @return PCNT threshold value
*/
static inline int pcnt_ll_get_thres_value(pcnt_dev_t *hw, uint32_t unit, uint32_t thres)
{
int16_t value;
typeof(hw->conf_unit[unit].conf1) conf1_reg = hw->conf_unit[unit].conf1;
if (thres == 0) {
value = conf1_reg.cnt_thres0;
} else {
value = conf1_reg.cnt_thres1;
}
return value;
}
/**
* @brief Get PCNT unit runtime status
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return PCNT unit runtime status
*/
static inline uint32_t pcnt_ll_get_unit_status(pcnt_dev_t *hw, uint32_t unit)
{
return hw->status_unit[unit].val;
}
/**
* @brief Get PCNT count sign
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return Count sign
*/
static inline pcnt_unit_count_sign_t pcnt_ll_get_count_sign(pcnt_dev_t *hw, uint32_t unit)
{
return hw->status_unit[unit].val & 0x03;
}
/**
* @brief Get PCNT event status
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return Event status word
*/
static inline uint32_t pcnt_ll_get_event_status(pcnt_dev_t *hw, uint32_t unit)
{
return hw->status_unit[unit].val >> 2;
}
/**
* @brief Set PCNT glitch filter threshold
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
* Any pulses lasting shorter than this will be ignored when the filter is enabled.
*/
static inline void pcnt_ll_set_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit, uint32_t filter_val)
{
hw->conf_unit[unit].conf0.filter_thres = filter_val;
}
/**
* @brief Get PCNT glitch filter threshold
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return glitch filter threshold
*/
static inline uint32_t pcnt_ll_get_glitch_filter_thres(pcnt_dev_t *hw, uint32_t unit)
{
return hw->conf_unit[unit].conf0.filter_thres;
}
/**
* @brief Enable PCNT glitch filter
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param enable True to enable the filter, False to disable the filter
*/
static inline void pcnt_ll_enable_glitch_filter(pcnt_dev_t *hw, uint32_t unit, bool enable)
{
hw->conf_unit[unit].conf0.filter_en = enable;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,361 @@
// Copyright 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.
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include "hal/misc.h"
#include "soc/rmt_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RMT_LL_HW_BASE (&RMT)
#define RMT_LL_MEM_BASE (&RMTMEM)
// 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)
{
dev->conf_ch[0].conf0.clk_en = enable;
}
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)
{
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)
{
dev->conf_ch[channel].conf1.ref_always_on = src;
}
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->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;
}
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;
}
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;
}
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].val = 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;
}
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;
}
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)
{
return dev->conf_ch[channel].conf0.mem_size;
}
static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf0.mem_size;
}
static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div);
}
static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt, div);
}
static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt);
return div == 0 ? 256 : div;
}
static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = HAL_FORCE_READ_U32_REG_FIELD(dev->conf_ch[channel].conf0, div_cnt);
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)
{
dev->conf_ch[channel].conf1.mem_owner = owner;
}
static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.mem_owner;
}
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)
{
return dev->conf_ch[channel].conf1.tx_conti_mode;
}
static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel)
{
// RMT on esp32 doesn't support loop count, adding this only for HAL API consistency
}
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)
{
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)
{
return dev->status_ch[channel];
}
static inline uint32_t rmt_ll_tx_get_channel_status(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));
}
static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x01) >> 0) | ((status & 0x08) >> 2) | ((status & 0x40) >> 4) | ((status & 0x200) >> 6) |
((status & 0x1000) >> 8) | ((status & 0x8000) >> 10) | ((status & 0x40000) >> 12) | ((status & 0x200000) >> 14);
}
static inline uint32_t rmt_ll_get_rx_end_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x02) >> 1) | ((status & 0x10) >> 3) | ((status & 0x80) >> 5) | ((status & 0x400) >> 7) |
((status & 0x2000) >> 9) | ((status & 0x10000) >> 11) | ((status & 0x80000) >> 13) | ((status & 0x400000) >> 15);
}
static inline uint32_t rmt_ll_get_tx_err_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x04) >> 2) | ((status & 0x20) >> 4) | ((status & 0x100) >> 6) | ((status & 0x800) >> 8) |
((status & 0x4000) >> 10) | ((status & 0x20000) >> 12) | ((status & 0x100000) >> 14) | ((status & 0x800000) >> 16);
}
static inline uint32_t rmt_ll_get_rx_err_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x04) >> 2) | ((status & 0x20) >> 4) | ((status & 0x100) >> 6) | ((status & 0x800) >> 8) |
((status & 0x4000) >> 10) | ((status & 0x20000) >> 12) | ((status & 0x100000) >> 14) | ((status & 0x800000) >> 16);
}
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
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

View File

@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc.h"
#include "soc/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t)
{
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX);
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32);
}
static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void)
{
REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR);
}
static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void)
{
return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
}
static inline void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
{
REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask);
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
}
static inline void rtc_cntl_ll_ulp_wakeup_enable(void)
{
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
}
static inline void rtc_cntl_ll_ulp_int_clear(void)
{
REG_SET_BIT(RTC_CNTL_INT_CLR_REG, RTC_CNTL_SAR_INT_CLR);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,362 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stdlib.h>
#include "soc/rtc_io_periph.h"
#include "soc/rtc_io_struct.h"
#include "hal/rtc_io_types.h"
#include "hal/gpio_types.h"
#define RTCIO_LL_PIN_FUNC 0
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */
RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */
} rtcio_ll_func_t;
typedef enum {
RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */
RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */
RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */
} rtcio_ll_wake_type_t;
typedef enum {
RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */
RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */
} rtcio_ll_out_mode_t;
/**
* @brief Select the rtcio function.
*
* @note The RTC function must be selected before the pad analog function is enabled.
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @param func Select pin function.
*/
static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func)
{
if (func == RTCIO_FUNC_RTC) {
// 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module.
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
//0:RTC FUNCTION 1,2,3:Reserved
SET_PERI_REG_BITS(rtc_io_desc[rtcio_num].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, RTCIO_LL_PIN_FUNC, rtc_io_desc[rtcio_num].func);
} else if (func == RTCIO_FUNC_DIGITAL) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
}
}
/**
* Enable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_output_enable(int rtcio_num)
{
RTCIO.enable_w1ts.w1ts = (1U << rtcio_num);
}
/**
* Disable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_output_disable(int rtcio_num)
{
RTCIO.enable_w1tc.w1tc = (1U << rtcio_num);
}
/**
* Set RTCIO output level.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @param level 0: output low; ~0: output high.
*/
static inline void rtcio_ll_set_level(int rtcio_num, uint32_t level)
{
if (level) {
RTCIO.out_w1ts.w1ts = (1U << rtcio_num);
} else {
RTCIO.out_w1tc.w1tc = (1U << rtcio_num);
}
}
/**
* Enable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_input_enable(int rtcio_num)
{
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].ie);
}
/**
* Disable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_input_disable(int rtcio_num)
{
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].ie);
}
/**
* Get RTCIO input level.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @return 0: input low; ~0: input high.
*/
static inline uint32_t rtcio_ll_get_level(int rtcio_num)
{
return (uint32_t)(RTCIO.in_val.in >> rtcio_num) & 0x1;
}
/**
* @brief Set RTC GPIO pad drive capability
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @param strength Drive capability of the pad. Range: 0 ~ 3.
*/
static inline void rtcio_ll_set_drive_capability(int rtcio_num, uint32_t strength)
{
if (rtc_io_desc[rtcio_num].drv_v) {
SET_PERI_REG_BITS(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].drv_v, strength, rtc_io_desc[rtcio_num].drv_s);
}
}
/**
* @brief Get RTC GPIO pad drive capability.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @return Drive capability of the pad. Range: 0 ~ 3.
*/
static inline uint32_t rtcio_ll_get_drive_capability(int rtcio_num)
{
return GET_PERI_REG_BITS2(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].drv_v, rtc_io_desc[rtcio_num].drv_s);
}
/**
* @brief Set RTC GPIO pad output mode.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @return mode Output mode.
*/
static inline void rtcio_ll_output_mode_set(int rtcio_num, rtcio_ll_out_mode_t mode)
{
RTCIO.pin[rtcio_num].pad_driver = mode;
}
/**
* RTC GPIO pullup enable.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_pullup_enable(int rtcio_num)
{
if (rtc_io_desc[rtcio_num].pullup) {
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pullup);
}
}
/**
* RTC GPIO pullup disable.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_pullup_disable(int rtcio_num)
{
if (rtc_io_desc[rtcio_num].pullup) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pullup);
}
}
/**
* RTC GPIO pulldown enable.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_pulldown_enable(int rtcio_num)
{
if (rtc_io_desc[rtcio_num].pulldown) {
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pulldown);
}
}
/**
* RTC GPIO pulldown disable.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_pulldown_disable(int rtcio_num)
{
if (rtc_io_desc[rtcio_num].pulldown) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pulldown);
}
}
/**
* Enable force hold function for RTC IO pad.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_force_hold_enable(int rtcio_num)
{
REG_SET_BIT(RTC_CNTL_HOLD_FORCE_REG, rtc_io_desc[rtcio_num].hold_force);
REG_SET_BIT(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].hold);
}
/**
* Disable hold function on an RTC IO pad
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_force_hold_disable(int rtcio_num)
{
REG_CLR_BIT(RTC_CNTL_HOLD_FORCE_REG, rtc_io_desc[rtcio_num].hold_force);
REG_CLR_BIT(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].hold);
}
/**
* Enable force hold function for RTC IO pad.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_force_hold_all(void)
{
SET_PERI_REG_BITS(RTC_CNTL_HOLD_FORCE_REG, 0x3FFFF, 0x3FFFF, 0);
}
/**
* Disable hold function on an RTC IO pad
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_force_unhold_all(void)
{
SET_PERI_REG_BITS(RTC_CNTL_HOLD_FORCE_REG, 0x3FFFF, 0, 0);
}
/**
* Enable wakeup function and set wakeup type from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @param type Wakeup on high level or low level.
*/
static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t type)
{
RTCIO.pin[rtcio_num].wakeup_enable = 0x1;
RTCIO.pin[rtcio_num].int_type = type;
}
/**
* Disable wakeup function from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_wakeup_disable(int rtcio_num)
{
RTCIO.pin[rtcio_num].wakeup_enable = 0;
RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE;
}
/**
* Enable rtc io output in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num)
{
if (rtc_io_desc[gpio_num].slpoe) {
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
}
}
/**
* Disable rtc io output in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_disable_output(gpio_num_t gpio_num)
{
if (rtc_io_desc[gpio_num].slpoe) {
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
}
}
/**
* Enable rtc io input in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_enable_input(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
}
/**
* Disable rtc io input in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_disable_input(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
}
/**
* Enable rtc io keep another setting in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
}
/**
* Disable rtc io keep another setting in deep sleep. (Default)
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
}
static inline void rtcio_ll_ext0_set_wakeup_pin(int rtcio_num, int level)
{
REG_SET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL, rtcio_num);
// Set level which will trigger wakeup
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
level , RTC_CNTL_EXT_WAKEUP0_LV_S);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,298 @@
// 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.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdbool.h>
#include "hal/wdt_types.h"
#include "soc/rtc_cntl_periph.h"
#include "soc/rtc_cntl_struct.h"
#include "esp_attr.h"
//Type check wdt_stage_action_t
_Static_assert(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
//Type check wdt_reset_sig_length_t
_Static_assert(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
/**
* @brief Enable the RWDT
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw)
{
hw->wdt_config0.en = 1;
}
/**
* @brief Disable the RWDT
*
* @param hw Start address of the peripheral registers.
* @note This function does not disable the flashboot mode. Therefore, given that
* the MWDT is disabled using this function, a timeout can still occur
* if the flashboot mode is simultaneously enabled.
*/
FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw)
{
hw->wdt_config0.en = 0;
}
/**
* @brief Check if the RWDT is enabled
*
* @param hw Start address of the peripheral registers.
* @return True if RTC WDT is enabled
*/
FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw)
{
return (hw->wdt_config0.en) ? true : false;
}
/**
* @brief Configure a particular stage of the RWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to configure
* @param timeout Number of timer ticks for the stage to timeout
* @param behavior What action to take when the stage times out
*/
FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = behavior;
hw->wdt_config1 = timeout_ticks;
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = behavior;
hw->wdt_config2 = timeout_ticks;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = behavior;
hw->wdt_config3 = timeout_ticks;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = behavior;
hw->wdt_config4 = timeout_ticks;
break;
default:
abort();
}
}
/**
* @brief Disable a particular stage of the RWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to disable
*/
FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
break;
default:
abort();
}
}
/**
* @brief Enable or disable RWDT edge interrupt
*
* @param hw Start address of the peripheral registers.
* @param enable Whether to enable edge interrupt
*/
FORCE_INLINE_ATTR void rwdt_ll_set_edge_intr(rtc_cntl_dev_t *hw, bool enable)
{
hw->wdt_config0.edge_int_en = (enable) ? 1 : 0;
}
/**
* @brief Enable or disable RWDT level interrupt
*
* @param hw Start address of the peripheral registers.
* @param enable Whether to enable level interrupt
*/
FORCE_INLINE_ATTR void rwdt_ll_set_level_intr(rtc_cntl_dev_t *hw, bool enable)
{
hw->wdt_config0.level_int_en = (enable) ? 1 : 0;
}
/**
* @brief Set the length of the CPU reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of CPU reset signal
*/
FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.cpu_reset_length = length;
}
/**
* @brief Set the length of the system reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of system reset signal
*/
FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.sys_reset_length = length;
}
/**
* @brief Enable/Disable the RWDT flashboot mode.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode.
*
* @note Flashboot mode is independent and can trigger a WDT timeout event if the
* WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled
* on flashboot, and should be disabled by software when flashbooting completes.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable CPU0 to be reset, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable CPU1 to be reset, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the RWDT pause during sleep functionality
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0;
}
/**
* @brief Feed the RWDT
*
* Resets the current timer count and current stage.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw)
{
hw->wdt_feed.feed = 1;
}
/**
* @brief Enable write protection of the RWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw)
{
hw->wdt_wprotect = 0;
}
/**
* @brief Disable write protection of the RWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw)
{
hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE;
}
/**
* @brief Enable the RWDT interrupt.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable RWDT interrupt, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable)
{
hw->int_ena.rtc_wdt = (enable) ? 1 : 0;
}
/**
* @brief Check if the RWDT interrupt has been triggered
*
* @param hw Start address of the peripheral registers.
* @return True if the RWDT interrupt was triggered
*/
FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw)
{
return (hw->int_st.rtc_wdt) ? true : false;
}
/**
* @brief Clear the RWDT interrupt status.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw)
{
hw->int_clr.rtc_wdt = 1;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,157 @@
// 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.
#pragma once
#include <stdbool.h>
#include "hal/sha_types.h"
#include "soc/hwcrypto_reg.h"
#include "soc/dport_access.h"
#include "hal/misc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SHA_LL_TYPE_OFFSET 0x10
/**
* @brief Returns the LOAD_REG register address for the given sha type
*
* @param sha_type The SHA algorithm type
* @return uint32_t the LOAD_REG register address
*/
inline static uint32_t SHA_LOAD_REG(esp_sha_type sha_type)
{
return SHA_1_LOAD_REG + sha_type * SHA_LL_TYPE_OFFSET;
}
/**
* @brief Returns the BUSY register address for the given sha type
*
* @param sha_type The SHA algorithm type
* @return uint32_t the BUSY register address
*/
inline static uint32_t SHA_BUSY_REG(esp_sha_type sha_type)
{
return SHA_1_BUSY_REG + sha_type * SHA_LL_TYPE_OFFSET;
}
/**
* @brief Returns the START register address for the given sha type
*
* @param sha_type The SHA algorithm type
* @return uint32_t the START register address
*/
inline static uint32_t SHA_START_REG(esp_sha_type sha_type)
{
return SHA_1_START_REG + sha_type * SHA_LL_TYPE_OFFSET;
}
/**
* @brief Returns the CONTINUE register address for the given sha type
*
* @param sha_type The SHA algorithm type
* @return uint32_t the CONTINUE register address
*/
inline static uint32_t SHA_CONTINUE_REG(esp_sha_type sha_type)
{
return SHA_1_CONTINUE_REG + sha_type * SHA_LL_TYPE_OFFSET;
}
/**
* @brief Start a new SHA block conversion (no initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_start_block(esp_sha_type sha_type)
{
DPORT_REG_WRITE(SHA_START_REG(sha_type), 1);
}
/**
* @brief Continue a SHA block conversion (initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_continue_block(esp_sha_type sha_type)
{
DPORT_REG_WRITE(SHA_CONTINUE_REG(sha_type), 1);
}
/**
* @brief Load the current hash digest to digest register
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_load(esp_sha_type sha_type)
{
DPORT_REG_WRITE(SHA_LOAD_REG(sha_type), 1);
}
/**
* @brief Checks if the SHA engine is currently busy hashing a block
*
* @return true SHA engine busy
* @return false SHA engine idle
*/
static inline bool sha_ll_busy(void)
{
return (DPORT_REG_READ(SHA_1_BUSY_REG) || DPORT_REG_READ(SHA_256_BUSY_REG)
|| DPORT_REG_READ(SHA_384_BUSY_REG) || DPORT_REG_READ(SHA_512_BUSY_REG));
}
/**
* @brief Write a text (message) block to the SHA engine
*
* @param input_text Input buffer to be written to the SHA engine
* @param block_word_len Number of words in block
*/
static inline void sha_ll_fill_text_block(const void *input_text, size_t block_word_len)
{
uint32_t *reg_addr_buf = NULL;
uint32_t *data_words = NULL;
reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
data_words = (uint32_t *)input_text;
for (size_t i = 0; i < block_word_len; i++) {
reg_addr_buf[i] = HAL_SWAP32(data_words[i]);
}
}
/**
* @brief Read the message digest from the SHA engine
*
* @param sha_type The SHA algorithm type
* @param digest_state Buffer that message digest will be written to
* @param digest_word_len Length of the message digest
*/
static inline void sha_ll_read_digest(esp_sha_type sha_type, void *digest_state, size_t digest_word_len)
{
uint32_t *digest_state_words = (uint32_t *)digest_state;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
if (sha_type == SHA2_384 || sha_type == SHA2_512) {
/* for these ciphers using 64-bit states, swap each pair of words */
DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU.
for (size_t i = 0; i < digest_word_len; i += 2) {
digest_state_words[i + 1] = DPORT_SEQUENCE_REG_READ((uint32_t)&reg_addr_buf[i]);
digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)&reg_addr_buf[i + 1]);
}
DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level
} else {
esp_dport_access_read_buffer(digest_state_words, (uint32_t)&reg_addr_buf[0], digest_word_len);
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,75 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 SIGMADELTA register operations
#pragma once
#include <stdbool.h>
#include "hal/misc.h"
#include "soc/sigmadelta_periph.h"
#include "soc/gpio_sd_struct.h"
#include "hal/sigmadelta_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get SIGMADELTA hardware instance with giving sigmadelta num
#define SIGMADELTA_LL_GET_HW(num) (((num) == 0) ? (&SIGMADELTA) : NULL)
/**
* @brief Set Sigma-delta enable
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param en Sigma-delta enable value
*/
static inline void sigmadelta_ll_set_en(gpio_sd_dev_t *hw, bool en)
{
// The clk enable register does not exist on ESP32.
}
/**
* @brief Set Sigma-delta channel duty.
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param channel Sigma-delta channel number
* @param duty Sigma-delta duty of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90.
* The waveform is more like a random one in this range.
*/
static inline void sigmadelta_ll_set_duty(gpio_sd_dev_t *hw, sigmadelta_channel_t channel, int8_t duty)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], duty, (uint32_t)duty);
}
/**
* @brief Set Sigma-delta channel's clock pre-scale value.
*
* @param hw Peripheral SIGMADELTA hardware instance address.
* @param channel Sigma-delta channel number
* @param val The divider of source clock, ranges from 0 to 255
*/
static inline void sigmadelta_ll_set_prescale(gpio_sd_dev_t *hw, sigmadelta_channel_t channel, uint8_t prescale)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[channel], prescale, prescale);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,54 @@
// 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.
#pragma once
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void soc_ll_stall_core(int core)
{
const int rtc_cntl_c1_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_M, RTC_CNTL_SW_STALL_APPCPU_C1_M};
const int rtc_cntl_c1_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_S, RTC_CNTL_SW_STALL_APPCPU_C1_S};
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_M, RTC_CNTL_SW_STALL_APPCPU_C0_M};
const int rtc_cntl_c0_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_S, RTC_CNTL_SW_STALL_APPCPU_C0_S};
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m[core]);
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21 << rtc_cntl_c1_s[core]);
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m[core]);
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2 << rtc_cntl_c0_s[core]);
}
static inline void soc_ll_unstall_core(int core)
{
const int rtc_cntl_c1_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_M, RTC_CNTL_SW_STALL_APPCPU_C1_M};
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_M, RTC_CNTL_SW_STALL_APPCPU_C0_M};
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m[core]);
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m[core]);
}
static inline void soc_ll_reset_core(int core)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
core == 0 ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,119 @@
// Copyright 2015-2021 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash Encryption.
#include "soc/dport_reg.h"
#include "soc/flash_encryption_reg.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Enable encryption in flash
*/
static inline void spi_flash_encrypt_ll_enable(void)
{
DPORT_REG_SET_BIT(DPORT_SLAVE_SPI_CONFIG_REG, DPORT_SLAVE_SPI_MASK_PRO | DPORT_SPI_ENCRYPT_ENABLE);
}
/**
* Disable encryption in flash
*/
static inline void spi_flash_encrypt_ll_disable(void)
{
DPORT_REG_CLR_BIT(DPORT_SLAVE_SPI_CONFIG_REG, DPORT_SLAVE_SPI_MASK_PRO | DPORT_SPI_ENCRYPT_ENABLE);
}
/**
* Copy the flash address to physical address
*
* @param flash_addr The flash address.
*
* @note the address must be 8-byte aligned
*/
static inline void spi_flash_encrypt_ll_address_save(uint32_t flash_addr)
{
REG_WRITE(FLASH_ENCRYPTION_ADDRESS_REG, flash_addr);
}
/**
* Wait for flash encryption operation completeness.
*/
static inline void spi_flash_encrypt_ll_calculate_wait_idle(void)
{
while(!(REG_READ(FLASH_ENCRYPTION_DONE_REG) & BIT(0))) {
}
}
/**
* Start encryption on data buffer.
*/
static inline void spi_flash_encrypt_ll_calculate_start(void)
{
REG_WRITE(FLASH_ENCRYPTION_START_REG, BIT(0));
}
/**
* Save the plaintext for encryption
*
* @param address address of the partition to be written.
* @param buffer Buffer to store the input data.
* @param size Buffer size.
*/
static inline void spi_flash_encrypt_ll_plaintext_save(uint32_t address, const uint32_t* buffer, uint32_t size)
{
for (int i = 0; i < 8; i++) {
REG_WRITE(FLASH_ENCRYPTION_BUFFER_REG + (i << 2), buffer[i]);
}
}
/**
* Finish the flash encryption and make encrypted result accessible to SPI.
*/
static inline void spi_flash_encrypt_ll_done(void)
{
// Do nothing on ESP32
}
/**
* Set to destroy encrypted result
*/
static inline void spi_flash_encrypt_ll_destroy(void)
{
// Do nothing on ESP32
}
/**
* Check if is qualified to encrypt the buffer
*
* @param address the address of written flash partition.
* @param length Buffer size.
*/
static inline bool spi_flash_encrypt_ll_check(uint32_t address, uint32_t length)
{
return ((address % 16) == 0) ? true : false;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,415 @@
// 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include <sys/param.h> // For MIN/MAX
#include <stdbool.h>
#include <string.h>
#include "hal/misc.h"
#ifdef __cplusplus
extern "C" {
#endif
//Supported clock register values
#define SPI_FLASH_LL_CLKREG_VAL_5MHZ ((spi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz
#define SPI_FLASH_LL_CLKREG_VAL_10MHZ ((spi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz
#define SPI_FLASH_LL_CLKREG_VAL_20MHZ ((spi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz
#define SPI_FLASH_LL_CLKREG_VAL_26MHZ ((spi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz
#define SPI_FLASH_LL_CLKREG_VAL_40MHZ ((spi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz
#define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/// Get the start address of SPI peripheral registers by the host ID
#define spi_flash_ll_get_hw(host_id) ( ((host_id)==SPI1_HOST) ? &SPI1 :(\
((host_id)==SPI2_HOST) ? &SPI2 :(\
((host_id)==SPI3_HOST) ? &SPI3 :(\
{abort();(spi_dev_t*)0;}\
))) )
#define spi_flash_ll_hw_get_id(dev) ( ((dev) == &SPI1) ? SPI1_HOST :(\
((dev) == &SPI2) ? SPI2_HOST :(\
((dev) == &SPI3) ? SPI3_HOST :(\
-1\
))) )
/// Empty function to be compatible with new version chips.
#define spi_flash_ll_set_dummy_out(dev, out_en, out_lev)
/// type to store pre-calculated register value in above layers
typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t;
/*------------------------------------------------------------------------------
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_reset(spi_dev_t *dev)
{
dev->user.val = 0;
dev->ctrl.val = 0;
}
/**
* Check whether the previous operation is done.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if last command is done, otherwise false.
*/
static inline bool spi_flash_ll_cmd_is_done(const spi_dev_t *dev)
{
return (dev->cmd.val == 0);
}
/**
* Erase the flash chip.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_erase_chip(spi_dev_t *dev)
{
dev->cmd.flash_ce = 1;
}
/**
* Erase the sector, the address should be set by spi_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_erase_sector(spi_dev_t *dev)
{
dev->ctrl.val = 0;
dev->cmd.flash_se = 1;
}
/**
* Erase the block, the address should be set by spi_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_erase_block(spi_dev_t *dev)
{
dev->cmd.flash_be = 1;
}
/**
* Enable/disable write protection for the flash chip.
*
* @param dev Beginning address of the peripheral registers.
* @param wp true to enable the protection, false to disable (write enable).
*/
static inline void spi_flash_ll_set_write_protect(spi_dev_t *dev, bool wp)
{
if (wp) {
dev->cmd.flash_wrdi = 1;
} else {
dev->cmd.flash_wren = 1;
}
}
/**
* Get the read data from the buffer after ``spi_flash_ll_read`` is done.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer to hold the output data
* @param read_len Length to get out of the buffer
*/
static inline void spi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len)
{
if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) {
// If everything is word-aligned, do a faster memcpy
memcpy(buffer, (void *)dev->data_buf, read_len);
} else {
// Otherwise, slow(er) path copies word by word
int copy_len = read_len;
for (size_t i = 0; i < (read_len + 3) / 4; i++) {
int word_len = MIN(sizeof(uint32_t), copy_len);
uint32_t word = dev->data_buf[i];
memcpy(buffer, &word, word_len);
buffer = (void *)((intptr_t)buffer + word_len);
copy_len -= word_len;
}
}
}
/**
* Write a word to the data buffer.
*
* @param dev Beginning address of the peripheral registers.
* @param word Data to write at address 0.
*/
static inline void spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word)
{
dev->data_buf[0] = word;
}
/**
* Set the data to be written in the data buffer.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer holding the data
* @param length Length of data in bytes.
*/
static inline void spi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length)
{
// Load data registers, word at a time
int num_words = (length + 3) >> 2;
for (int i = 0; i < num_words; i++) {
uint32_t word = 0;
uint32_t word_len = MIN(length, sizeof(word));
memcpy(&word, buffer, word_len);
dev->data_buf[i] = word;
length -= word_len;
buffer = (void *)((intptr_t)buffer + word_len);
}
}
/**
* Program a page of the flash chip. Call ``spi_flash_ll_set_address`` before
* this to set the address to program.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer holding the data to program
* @param length Length to program.
*/
static inline void spi_flash_ll_program_page(spi_dev_t *dev, const void *buffer, uint32_t length)
{
dev->user.usr_dummy = 0;
spi_flash_ll_set_buffer_data(dev, buffer, length);
dev->cmd.flash_pp = 1;
}
/**
* Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases,
* should be configured before this is called.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spi_flash_ll_user_start(spi_dev_t *dev)
{
dev->cmd.usr = 1;
}
/**
* Check whether the host is idle to perform new commands.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if the host is idle, otherwise false
*/
static inline bool spi_flash_ll_host_idle(const spi_dev_t *dev)
{
return dev->ext2.st == 0;
}
/*------------------------------------------------------------------------------
* Configs
*----------------------------------------------------------------------------*/
/**
* Select which pin to use for the flash
*
* @param dev Beginning address of the peripheral registers.
* @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins.
*/
static inline void spi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin)
{
dev->pin.cs0_dis = (pin != 0);
dev->pin.cs1_dis = (pin != 1);
dev->pin.cs2_dis = (pin != 2);
}
/**
* Set the read io mode.
*
* @param dev Beginning address of the peripheral registers.
* @param read_mode I/O mode to use in the following transactions.
*/
static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
ctrl.val &= ~(SPI_FREAD_QIO_M | SPI_FREAD_QUAD_M | SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M);
ctrl.val |= SPI_FASTRD_MODE_M;
switch (read_mode) {
case SPI_FLASH_FASTRD:
//the default option
break;
case SPI_FLASH_QIO:
ctrl.fread_qio = 1;
break;
case SPI_FLASH_QOUT:
ctrl.fread_quad = 1;
break;
case SPI_FLASH_DIO:
ctrl.fread_dio = 1;
break;
case SPI_FLASH_DOUT:
ctrl.fread_dual = 1;
break;
case SPI_FLASH_SLOWRD:
ctrl.fastrd_mode = 0;
break;
default:
abort();
}
dev->ctrl = ctrl;
}
/**
* Set clock frequency to work at.
*
* @param dev Beginning address of the peripheral registers.
* @param clock_val pointer to the clock value to set
*/
static inline void spi_flash_ll_set_clock(spi_dev_t *dev, spi_flash_ll_clock_reg_t *clock_val)
{
dev->clock = *clock_val;
}
/**
* Set the input length, in bits.
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of input, in bits.
*/
static inline void spi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
dev->miso_dlen.usr_miso_dbitlen = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the output length, in bits (not including command, address and dummy
* phases)
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of output, in bits.
*/
static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
dev->mosi_dlen.usr_mosi_dbitlen = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void spi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
/**
* Get the address length that is set in register, in bits.
*
* @param dev Beginning address of the peripheral registers.
*
*/
static inline int spi_flash_ll_get_addr_bitlen(spi_dev_t *dev)
{
return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0;
}
/**
* Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of the address, in bits
*/
static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user1.usr_addr_bitlen = (bitlen - 1);
dev->user.usr_addr = bitlen ? 1 : 0;
}
/**
* Set the address to send in user command mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, int bit_len)
{
// The blank region should be all ones
if (bit_len >= 32) {
dev->addr = addr;
dev->slv_wr_status = UINT32_MAX;
} else {
uint32_t padding_ones = (bit_len == 32? 0 : UINT32_MAX >> bit_len);
dev->addr = (addr << (32 - bit_len)) | padding_ones;
}
}
/**
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr)
{
dev->addr = addr;
}
/**
* Set the length of dummy cycles.
*
* @param dev Beginning address of the peripheral registers.
* @param dummy_n Cycles of dummy phases
*/
static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
{
dev->user.usr_dummy = dummy_n ? 1 : 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user1, usr_dummy_cyclelen, dummy_n - 1);
}
static inline void spi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.hold_time = hold_n;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
static inline void spi_flash_ll_set_cs_setup(spi_dev_t *dev, uint32_t cs_setup_time)
{
dev->user.cs_setup = (cs_setup_time > 0 ? 1 : 0);
dev->ctrl2.setup_time = cs_setup_time - 1;
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,401 @@
// 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.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "hal/timer_types.h"
#include "soc/timer_periph.h"
#include "soc/timer_group_struct.h"
_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
// Get timer group instance with giving group number
#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1))
/**
* @brief Set timer clock prescale value
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param divider Prescale value (0 and 1 are not valid)
*
* @return None
*/
static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider)
{
HAL_ASSERT(divider >= 2 && divider <= 65536);
if (divider >= 65536) {
divider = 0;
}
int timer_en = hw->hw_timer[timer_num].config.enable;
hw->hw_timer[timer_num].config.enable = 0;
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hw_timer[timer_num].config, divider, divider);
hw->hw_timer[timer_num].config.enable = timer_en;
}
/**
* @brief Get timer clock prescale value
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param divider Pointer to accept the prescale value
*
* @return None
*/
static inline void timer_ll_get_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t *divider)
{
uint32_t d = HAL_FORCE_READ_U32_REG_FIELD(hw->hw_timer[timer_num].config, divider);
if (d == 0) {
d = 65536;
} else if (d == 1) {
d = 2;
}
*divider = d;
}
/**
* @brief Load counter value into time-base counter
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param load_val Counter value
*
* @return None
*/
static inline void timer_ll_set_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t load_val)
{
hw->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
hw->hw_timer[timer_num].load_low = (uint32_t) load_val;
hw->hw_timer[timer_num].reload = 1;
}
/**
* @brief Get counter value from time-base counter
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param timer_val Pointer to accept the counter value
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
{
hw->hw_timer[timer_num].update = 1;
while (hw->hw_timer[timer_num].update) {}
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
}
/**
* @brief Set counter mode, include increment mode and decrement mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param increase_en True to increment mode, fasle to decrement mode
*
* @return None
*/
static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en)
{
hw->hw_timer[timer_num].config.increase = increase_en;
}
/**
* @brief Get counter mode, include increment mode and decrement mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Increment mode
* - false Decrement mode
*/
static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.increase;
}
/**
* @brief Set counter status, enable or disable counter.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param counter_en True to enable counter, false to disable counter
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en)
{
hw->hw_timer[timer_num].config.enable = counter_en;
}
/**
* @brief Get counter status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable counter
* - false Disable conuter
*/
static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.enable;
}
/**
* @brief Set auto reload mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
*
* @return None
*/
static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en)
{
hw->hw_timer[timer_num].config.autoreload = auto_reload_en;
}
/**
* @brief Get auto reload mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable auto reload mode
* - false Disable auto reload mode
*/
FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.autoreload;
}
/**
* @brief Set the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Counter value to trigger the alarm
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
{
hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
}
/**
* @brief Get the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Pointer to accept the counter value to trigger the alarm
*
* @return None
*/
static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value)
{
*alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low);
}
/**
* @brief Set the alarm status, enable or disable the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_en True to enable alarm, false to disable alarm
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
{
hw->hw_timer[timer_num].config.alarm_en = alarm_en;
}
/**
* @brief Get the alarm status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable alarm
* - false Disable alarm
*/
static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.alarm_en;
}
/**
* @brief Enable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_ena.val |= BIT(timer_num);
hw->hw_timer[timer_num].config.level_int_en = 1;
}
/**
* @brief Disable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_ena.val &= (~BIT(timer_num));
hw->hw_timer[timer_num].config.level_int_en = 0;
}
/**
* @brief Disable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_clr_timers.val |= BIT(timer_num);
}
/**
* @brief Get interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param intr_status Interrupt status
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status)
{
*intr_status = hw->int_st_timers.val & 0x03;
}
/**
* @brief Get interrupt raw status.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_raw_status Interrupt raw status
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status)
{
timg_dev_t *hw = TIMER_LL_GET_HW(group_num);
*intr_raw_status = hw->int_raw.val & 0x03;
}
/**
* @brief Set the level interrupt status, enable or disable the level interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param level_int_en True to enable level interrupt, false to disable level interrupt
*
* @return None
*/
static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en)
{
hw->hw_timer[timer_num].config.level_int_en = level_int_en;
}
/**
* @brief Get the level interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable level interrupt
* - false Disable level interrupt
*/
static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.level_int_en;
}
/**
* @brief Set the edge interrupt status, enable or disable the edge interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
*
* @return None
*/
static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en)
{
hw->hw_timer[timer_num].config.edge_int_en = edge_int_en;
}
/**
* @brief Get the edge interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable edge interrupt
* - false Disable edge interrupt
*/
static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.edge_int_en;
}
/**
* @brief Get interrupt status register address.
*
* @param hw Beginning address of the peripheral registers.
*
* @return Interrupt status register address
*/
static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw)
{
return (uint32_t) & (hw->int_st_timers.val);
}
static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num)
{
return (1U << timer_num);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,135 @@
// Copyright 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for touch sensor (esp32 specific part)
#pragma once
#include "hal/touch_sensor_ll.h"
#include "hal/touch_sensor_types.h"
#include_next "hal/touch_sensor_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Set touch sensor measurement time.
*
* @param meas_time The duration of the touch sensor measurement.
* t_meas = meas_time / (8MHz), the maximum measure time is 0xffff / 8M = 8.19 ms.
*/
#define touch_hal_set_meas_time(meas_time) touch_ll_set_meas_time(meas_time)
/**
* Get touch sensor measurement time.
*
* @param meas_time Pointer to accept measurement cycle count.
*/
#define touch_hal_get_meas_time(meas_time) touch_ll_get_meas_time(meas_time)
/**
* Set touch sensor interrupt trigger mode.
* Interrupt can be triggered either when touch value is less than
* threshold or when touch value is more than threshold.
*
* @param mode Touch sensor interrupt trigger mode.
*/
#define touch_hal_set_trigger_mode(mode) touch_ll_set_trigger_mode(mode)
/**
* Get touch sensor interrupt trigger mode.
* Interrupt can be triggered either when touch value is less than
* threshold or when touch value is more than threshold.
*
* @param mode Touch sensor interrupt trigger mode.
*/
#define touch_hal_get_trigger_mode(mode) touch_ll_get_trigger_mode(mode)
/**
* Set touch sensor interrupt trigger source. There are two sets of touch signals.
* Set1 and set2 can be mapped to several touch signals. Either set will be triggered
* if at least one of its touch signal is 'touched'. The interrupt can be configured to be generated
* if set1 is triggered, or only if both sets are triggered.
*
* @param src Touch sensor interrupt trigger source.
*/
#define touch_hal_set_trigger_source(src) touch_ll_set_trigger_source(src)
/**
* Get touch sensor interrupt trigger source.
*
* @param src Pointer to accept touch sensor interrupt trigger source.
*/
#define touch_hal_get_trigger_source(src) touch_ll_get_trigger_source(src)
/**
* Set touch sensor group mask.
* Touch pad module has two sets of signals, 'Touched' signal is triggered only if
* at least one of touch pad in this group is "touched".
* This function will set the register bits according to the given bitmask.
*
* @param set1_mask bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask bitmask of touch sensor signal group2, it's a 10-bit value
*/
#define touch_hal_set_group_mask(group1_mask, group2_mask) touch_ll_set_group_mask(group1_mask, group2_mask)
/**
* Get touch sensor group mask.
*
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
*/
#define touch_hal_get_group_mask(group1_mask, group2_mask) touch_ll_get_group_mask(group1_mask, group2_mask)
/**
* Clear touch sensor group mask.
*
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
*/
#define touch_hal_clear_group_mask(group1_mask, group2_mask) touch_ll_clear_group_mask(group1_mask, group2_mask)
/**
* To enable touch pad interrupt.
*/
#define touch_hal_intr_enable() touch_ll_intr_enable()
/**
* To disable touch pad interrupt.
*/
#define touch_hal_intr_disable() touch_ll_intr_disable()
/**
* To clear touch pad interrupt.
*/
#define touch_hal_intr_clear() touch_ll_intr_clear()
/**
* Get the touch pad which caused wakeup from deep sleep.
*
* @param pad_num pointer to touch pad which caused wakeup.
*/
void touch_hal_get_wakeup_status(touch_pad_t *pad_num);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,513 @@
// 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for Touch Sensor
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include "hal/misc.h"
#include "soc/touch_sensor_periph.h"
#include "soc/sens_struct.h"
#include "soc/rtc_io_struct.h"
#include "soc/rtc_cntl_struct.h"
#include "hal/touch_sensor_types.h"
#ifdef __cplusplus
extern "C" {
#endif
//Some register bits of touch sensor 8 and 9 are mismatched, we need to swap the bits.
#define TOUCH_LL_BIT_SWAP(data, n, m) (((data >> n) & 0x1) == ((data >> m) & 0x1) ? (data) : ((data) ^ ((0x1 <<n) | (0x1 << m))))
#define TOUCH_LL_BITS_SWAP(v) TOUCH_LL_BIT_SWAP(v, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9)
/**
* Swap the number of touch8 and touch9.
*
* @touch_num Touch channel num.
*/
static inline touch_pad_t touch_ll_num_wrap(touch_pad_t touch_num)
{
if (touch_num == TOUCH_PAD_NUM8) {
return TOUCH_PAD_NUM9;
} else if (touch_num == TOUCH_PAD_NUM9) {
return TOUCH_PAD_NUM8;
}
return touch_num;
}
/**
* Set touch sensor measurement time.
*
* @param meas_time The duration of the touch sensor measurement.
* t_meas = meas_time / (8MHz), the maximum measure time is 0xffff / 8M = 8.19 ms.
*/
static inline void touch_ll_set_meas_time(uint16_t meas_time)
{
//touch sensor measure time= meas_cycle / 8Mhz
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_touch_ctrl1, touch_meas_delay, meas_time);
//the waiting cycles (in 8MHz) between TOUCH_START and TOUCH_XPD
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_touch_ctrl1, touch_xpd_wait, SOC_TOUCH_PAD_MEASURE_WAIT_MAX);
}
/**
* Get touch sensor measurement time.
*
* @param meas_time Pointer to accept measurement cycle count.
*/
static inline void touch_ll_get_meas_time(uint16_t *meas_time)
{
*meas_time = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_ctrl1, touch_meas_delay);
}
/**
* Set touch sensor sleep time (interval of measurement).
*
* @param sleep_time The touch sensor will sleep after each measurement.
* sleep_cycle decide the interval between each measurement.
* t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).
* The approximate frequency value of RTC_SLOW_CLK can be obtained using `rtc_clk_slow_freq_get_hz` function.
*/
static inline void touch_ll_set_sleep_time(uint16_t sleep_time)
{
//touch sensor sleep cycle Time = sleep_cycle / RTC_SLOW_CLK( can be 150k or 32k depending on the options)
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.sar_touch_ctrl2, touch_sleep_cycles, sleep_time);
}
/**
* Get touch sensor sleep time.
*
* @param sleep_time Pointer to accept sleep cycle count.
*/
static inline void touch_ll_get_sleep_time(uint16_t *sleep_time)
{
*sleep_time = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_ctrl2, touch_sleep_cycles);
}
/**
* Set touch sensor high voltage threshold of chanrge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So the high threshold should be less than the supply voltage.
*
* @param refh The high voltage threshold of chanrge.
*/
static inline void touch_ll_set_voltage_high(touch_high_volt_t refh)
{
RTCIO.touch_cfg.drefh = refh;
}
/**
* Get touch sensor high voltage threshold of chanrge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So the high threshold should be less than the supply voltage.
*
* @param refh The high voltage threshold of chanrge.
*/
static inline void touch_ll_get_voltage_high(touch_high_volt_t *refh)
{
*refh = (touch_high_volt_t)RTCIO.touch_cfg.drefh;
}
/**
* Set touch sensor low voltage threshold of discharge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
*
* @param refl The low voltage threshold of discharge.
*/
static inline void touch_ll_set_voltage_low(touch_low_volt_t refl)
{
RTCIO.touch_cfg.drefl = refl;
}
/**
* Get touch sensor low voltage threshold of discharge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
*
* @param refl The low voltage threshold of discharge.
*/
static inline void touch_ll_get_voltage_low(touch_low_volt_t *refl)
{
*refl = (touch_low_volt_t)RTCIO.touch_cfg.drefl;
}
/**
* Set touch sensor high voltage attenuation of chanrge. The actual charge threshold is high voltage threshold minus attenuation value.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So the high threshold should be less than the supply voltage.
*
* @param refh The high voltage threshold of chanrge.
*/
static inline void touch_ll_set_voltage_attenuation(touch_volt_atten_t atten)
{
RTCIO.touch_cfg.drange = atten;
}
/**
* Get touch sensor high voltage attenuation of chanrge. The actual charge threshold is high voltage threshold minus attenuation value.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So the high threshold should be less than the supply voltage.
*
* @param refh The high voltage threshold of chanrge.
*/
static inline void touch_ll_get_voltage_attenuation(touch_volt_atten_t *atten)
{
*atten = (touch_volt_atten_t)RTCIO.touch_cfg.drange;
}
/**
* Set touch sensor charge/discharge speed(currents) for each pad.
* If the slope is 0, the counter would always be zero.
* If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.
* If the slope is set 7, which is the maximum value, the charging and discharging would be fast.
* The measurement time becomes shorter.
*
* @note The higher the charge and discharge current, the greater the immunity of the touch channel,
* but it will increase the system power consumption.
* @param touch_num Touch pad index.
* @param slope touch pad charge/discharge speed(currents).
*/
static inline void touch_ll_set_slope(touch_pad_t touch_num, touch_cnt_slope_t slope)
{
RTCIO.touch_pad[touch_num].dac = slope;
}
/**
* Get touch sensor charge/discharge speed(currents) for each pad.
* If the slope is 0, the counter would always be zero.
* If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.
* If the slope is set 7, which is the maximum value, the charging and discharging would be fast.
* The measurement time becomes shorter.
*
* @param touch_num Touch pad index.
* @param slope touch pad charge/discharge speed(currents).
*/
static inline void touch_ll_get_slope(touch_pad_t touch_num, touch_cnt_slope_t *slope)
{
*slope = (touch_cnt_slope_t)RTCIO.touch_pad[touch_num].dac;
}
/**
* Set initial voltage state of touch channel for each measurement.
*
* @param touch_num Touch pad index.
* @param opt Initial voltage state.
*/
static inline void touch_ll_set_tie_option(touch_pad_t touch_num, touch_tie_opt_t opt)
{
touch_pad_t touch_pad_wrap = touch_ll_num_wrap(touch_num);
RTCIO.touch_pad[touch_pad_wrap].tie_opt = opt;
}
/**
* Get initial voltage state of touch channel for each measurement.
*
* @param touch_num Touch pad index.
* @param opt Initial voltage state.
*/
static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_t *opt)
{
touch_pad_t touch_pad_wrap = touch_ll_num_wrap(touch_num);
*opt = (touch_tie_opt_t)RTCIO.touch_pad[touch_pad_wrap].tie_opt;
}
/**
* Set touch sensor FSM mode.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode)
{
SENS.sar_touch_ctrl2.touch_start_fsm_en = 1;
SENS.sar_touch_ctrl2.touch_start_en = 0;
SENS.sar_touch_ctrl2.touch_start_force = mode;
}
/**
* Get touch sensor FSM mode.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
static inline void touch_ll_get_fsm_mode(touch_fsm_mode_t *mode)
{
*mode = (touch_fsm_mode_t)SENS.sar_touch_ctrl2.touch_start_force;
}
/**
* Start touch sensor FSM timer.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
static inline void touch_ll_start_fsm(void)
{
RTCCNTL.state0.touch_slp_timer_en = 1;
}
/**
* Stop touch sensor FSM timer.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
static inline void touch_ll_stop_fsm(void)
{
RTCCNTL.state0.touch_slp_timer_en = 0;
}
/**
* Trigger a touch sensor measurement, only support in SW mode of FSM.
*/
static inline void touch_ll_start_sw_meas(void)
{
SENS.sar_touch_ctrl2.touch_start_en = 0;
SENS.sar_touch_ctrl2.touch_start_en = 1;
}
/**
* Set touch sensor interrupt threshold.
*
* @note Refer to `touch_pad_set_trigger_mode` to see how to set trigger mode.
* @param touch_num touch pad index.
* @param threshold threshold of touchpad count.
*/
static inline void touch_ll_set_threshold(touch_pad_t touch_num, uint16_t threshold)
{
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
if (tp_wrap & 0x1) {
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.touch_thresh[tp_wrap / 2], l_thresh, threshold);
} else {
HAL_FORCE_MODIFY_U32_REG_FIELD(SENS.touch_thresh[tp_wrap / 2], h_thresh, threshold);
}
}
/**
* Get touch sensor interrupt threshold.
*
* @param touch_num touch pad index.
* @param threshold pointer to accept threshold.
*/
static inline void touch_ll_get_threshold(touch_pad_t touch_num, uint16_t *threshold)
{
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
if (threshold) {
*threshold = (tp_wrap & 0x1 ) ?
HAL_FORCE_READ_U32_REG_FIELD(SENS.touch_thresh[tp_wrap / 2], l_thresh) :
HAL_FORCE_READ_U32_REG_FIELD(SENS.touch_thresh[tp_wrap / 2], h_thresh);
}
}
/**
* Set touch sensor interrupt trigger mode.
* Interrupt can be triggered either when touch value is less than
* threshold or when touch value is more than threshold.
*
* @param mode Touch sensor interrupt trigger mode.
*/
static inline void touch_ll_set_trigger_mode(touch_trigger_mode_t mode)
{
SENS.sar_touch_ctrl1.touch_out_sel = mode;
}
/**
* Get touch sensor interrupt trigger mode.
* Interrupt can be triggered either when touch value is less than
* threshold or when touch value is more than threshold.
*
* @param mode Touch sensor interrupt trigger mode.
*/
static inline void touch_ll_get_trigger_mode(touch_trigger_mode_t *mode)
{
*mode = (touch_trigger_mode_t)SENS.sar_touch_ctrl1.touch_out_sel;
}
/**
* Set touch sensor interrupt trigger source. There are two sets of touch signals.
* Set1 and set2 can be mapped to several touch signals. Either set will be triggered
* if at least one of its touch signal is 'touched'. The interrupt can be configured to be generated
* if set1 is triggered, or only if both sets are triggered.
*
* @param src Touch sensor interrupt trigger source.
*/
static inline void touch_ll_set_trigger_source(touch_trigger_src_t src)
{
SENS.sar_touch_ctrl1.touch_out_1en = src;
}
/**
* Get touch sensor interrupt trigger source.
*
* @param src Pointer to accept touch sensor interrupt trigger source.
*/
static inline void touch_ll_get_trigger_source(touch_trigger_src_t *src)
{
*src = (touch_trigger_src_t)SENS.sar_touch_ctrl1.touch_out_1en;
}
/**
* Enable touch sensor channel. Register touch channel into touch sensor measurement group.
* The working mode of the touch sensor is simultaneous measurement.
* This function will set the measure bits according to the given bitmask.
*
* @note If set this mask, the FSM timer should be stop firsty.
* @note The touch sensor that in scan map, should be deinit GPIO function firstly.
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
* @return
* - ESP_OK on success
*/
static inline void touch_ll_set_channel_mask(uint16_t enable_mask)
{
SENS.sar_touch_enable.touch_pad_worken |= TOUCH_LL_BITS_SWAP(enable_mask);
}
/**
* Get touch sensor channel mask.
*
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
*/
static inline void touch_ll_get_channel_mask(uint16_t *enable_mask)
{
*enable_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_worken);
}
/**
* Disable touch sensor channel by bitmask.
*
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
*/
static inline void touch_ll_clear_channel_mask(uint16_t disable_mask)
{
SENS.sar_touch_enable.touch_pad_worken &= TOUCH_LL_BITS_SWAP(~disable_mask);
}
/**
* Set touch sensor group mask.
* Touch pad module has two sets of signals, 'Touched' signal is triggered only if
* at least one of touch pad in this group is "touched".
* This function will set the register bits according to the given bitmask.
*
* @param set1_mask bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask bitmask of touch sensor signal group2, it's a 10-bit value
*/
static inline void touch_ll_set_group_mask(uint16_t group1_mask, uint16_t group2_mask)
{
SENS.sar_touch_enable.touch_pad_outen1 |= TOUCH_LL_BITS_SWAP(group1_mask);
SENS.sar_touch_enable.touch_pad_outen2 |= TOUCH_LL_BITS_SWAP(group2_mask);
}
/**
* Get touch sensor group mask.
*
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
*/
static inline void touch_ll_get_group_mask(uint16_t *group1_mask, uint16_t *group2_mask)
{
*group1_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_outen1);
*group2_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_outen2);
}
/**
* Clear touch sensor group mask.
*
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
*/
static inline void touch_ll_clear_group_mask(uint16_t group1_mask, uint16_t group2_mask)
{
SENS.sar_touch_enable.touch_pad_outen1 &= TOUCH_LL_BITS_SWAP(~group1_mask);
SENS.sar_touch_enable.touch_pad_outen2 &= TOUCH_LL_BITS_SWAP(~group2_mask);
}
/**
* Get the touch sensor status, usually used in ISR to decide which pads are 'touched'.
*
* @param status_mask The touch sensor status. e.g. Touch1 trigger status is `status_mask & (BIT1)`.
*/
static inline void touch_ll_read_trigger_status_mask(uint32_t *status_mask)
{
*status_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_ctrl2.touch_meas_en);
}
/**
* Clear all touch sensor status.
*/
static inline void touch_ll_clear_trigger_status_mask(void)
{
SENS.sar_touch_ctrl2.touch_meas_en_clr = 1;
}
/**
* To enable touch pad interrupt.
*/
static inline void touch_ll_intr_enable(void)
{
RTCCNTL.int_ena.rtc_touch = 1;
}
/**
* To disable touch pad interrupt.
*/
static inline void touch_ll_intr_disable(void)
{
RTCCNTL.int_ena.rtc_touch = 0;
}
/**
* To clear touch pad interrupt.
*/
static inline void touch_ll_intr_clear(void)
{
RTCCNTL.int_clr.rtc_touch = 1;
}
/**
* Get touch sensor raw data (touch sensor counter value) from register. No block.
*
* @param touch_num touch pad index.
* @return touch_value pointer to accept touch sensor value.
*/
static inline uint32_t touch_ll_read_raw_data(touch_pad_t touch_num)
{
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
return ((tp_wrap & 0x1) ? HAL_FORCE_READ_U32_REG_FIELD(SENS.touch_meas[tp_wrap / 2], l_val) :
HAL_FORCE_READ_U32_REG_FIELD(SENS.touch_meas[tp_wrap / 2], h_val));
}
/**
* Get touch sensor measure status. No block.
*
* @return
* - If touch sensors measure done.
*/
static inline bool touch_ll_meas_is_done(void)
{
return (bool)SENS.sar_touch_ctrl2.touch_meas_done;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,28 @@
// 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.
#pragma once
#include "soc/dport_reg.h"
static inline void trace_ll_mem_enable(int cpu, bool enable)
{
int reg[] = {DPORT_PRO_TRACEMEM_ENA_REG, DPORT_APP_TRACEMEM_ENA_REG};
DPORT_WRITE_PERI_REG(reg[cpu], enable);
}
static inline void trace_ll_set_mode(int mode)
{
DPORT_WRITE_PERI_REG(DPORT_TRACEMEM_MUX_MODE_REG, mode);
}

View File

@@ -0,0 +1,836 @@
// 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.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for TWAI
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "hal/misc.h"
#include "hal/twai_types.h"
#include "soc/twai_periph.h"
#include "soc/twai_struct.h"
/* ------------------------- Defines and Typedefs --------------------------- */
#define TWAI_LL_STATUS_RBS (0x1 << 0) //Receive Buffer Status
#define TWAI_LL_STATUS_DOS (0x1 << 1) //Data Overrun Status
#define TWAI_LL_STATUS_TBS (0x1 << 2) //Transmit Buffer Status
#define TWAI_LL_STATUS_TCS (0x1 << 3) //Transmission Complete Status
#define TWAI_LL_STATUS_RS (0x1 << 4) //Receive Status
#define TWAI_LL_STATUS_TS (0x1 << 5) //Transmit Status
#define TWAI_LL_STATUS_ES (0x1 << 6) //Error Status
#define TWAI_LL_STATUS_BS (0x1 << 7) //Bus Status
#define TWAI_LL_INTR_RI (0x1 << 0) //Receive Interrupt
#define TWAI_LL_INTR_TI (0x1 << 1) //Transmit Interrupt
#define TWAI_LL_INTR_EI (0x1 << 2) //Error Interrupt
//Data overrun interrupt not supported in SW due to HW peculiarities
#define TWAI_LL_INTR_EPI (0x1 << 5) //Error Passive Interrupt
#define TWAI_LL_INTR_ALI (0x1 << 6) //Arbitration Lost Interrupt
#define TWAI_LL_INTR_BEI (0x1 << 7) //Bus Error Interrupt
/*
* The following frame structure has an NEARLY identical bit field layout to
* each byte of the TX buffer. This allows for formatting and parsing frames to
* be done outside of time critical regions (i.e., ISRs). All the ISR needs to
* do is to copy byte by byte to/from the TX/RX buffer. The two reserved bits in
* TX buffer are used in the frame structure to store the self_reception and
* single_shot flags which in turn indicate the type of transmission to execute.
*/
typedef union {
struct {
struct {
uint8_t dlc: 4; //Data length code (0 to 8) of the frame
uint8_t self_reception: 1; //This frame should be transmitted using self reception command
uint8_t single_shot: 1; //This frame should be transmitted using single shot command
uint8_t rtr: 1; //This frame is a remote transmission request
uint8_t frame_format: 1; //Format of the frame (1 = extended, 0 = standard)
};
union {
struct {
uint8_t id[2]; //11 bit standard frame identifier
uint8_t data[8]; //Data bytes (0 to 8)
uint8_t reserved8[2];
} standard;
struct {
uint8_t id[4]; //29 bit extended frame identifier
uint8_t data[8]; //Data bytes (0 to 8)
} extended;
};
};
uint8_t bytes[13];
} __attribute__((packed)) twai_ll_frame_buffer_t;
_Static_assert(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type should be 13 bytes");
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
/**
* Some errata workarounds will require a hardware reset of the peripheral. Thus
* certain registers must be saved before the reset, and then restored after the
* reset. This structure is used to hold some of those registers.
*/
typedef struct {
uint8_t mode_reg;
uint8_t interrupt_enable_reg;
uint8_t bus_timing_0_reg;
uint8_t bus_timing_1_reg;
uint8_t error_warning_limit_reg;
uint8_t acr_reg[4];
uint8_t amr_reg[4];
uint8_t rx_error_counter_reg;
uint8_t tx_error_counter_reg;
uint8_t clock_divider_reg;
} __attribute__((packed)) twai_ll_reg_save_t;
#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
#ifdef CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID
typedef enum {
TWAI_LL_ERR_BIT = 0,
TWAI_LL_ERR_FORM,
TWAI_LL_ERR_STUFF,
TWAI_LL_ERR_OTHER,
TWAI_LL_ERR_MAX,
} twai_ll_err_type_t;
typedef enum {
TWAI_LL_ERR_DIR_TX = 0,
TWAI_LL_ERR_DIR_RX,
TWAI_LL_ERR_DIR_MAX,
} twai_ll_err_dir_t;
typedef enum {
TWAI_LL_ERR_SEG_SOF = 0,
TWAI_LL_ERR_SEG_ID_28_21 = 2,
TWAI_LL_ERR_SEG_SRTR = 4,
TWAI_LL_ERR_SEG_IDE = 5,
TWAI_LL_ERR_SEG_ID_20_18 = 6,
TWAI_LL_ERR_SEG_ID_17_13 = 7,
TWAI_LL_ERR_SEG_CRC_SEQ = 8,
TWAI_LL_ERR_SEG_R0 = 9,
TWAI_LL_ERR_SEG_DATA = 10,
TWAI_LL_ERR_SEG_DLC = 11,
TWAI_LL_ERR_SEG_RTR = 12,
TWAI_LL_ERR_SEG_R1 = 13,
TWAI_LL_ERR_SEG_ID_4_0 = 14,
TWAI_LL_ERR_SEG_ID_12_5 = 15,
TWAI_LL_ERR_SEG_ACT_FLAG = 17,
TWAI_LL_ERR_SEG_INTER = 18,
TWAI_LL_ERR_SEG_SUPERPOS = 19,
TWAI_LL_ERR_SEG_PASS_FLAG = 22,
TWAI_LL_ERR_SEG_ERR_DELIM = 23,
TWAI_LL_ERR_SEG_CRC_DELIM = 24,
TWAI_LL_ERR_SEG_ACK_SLOT = 25,
TWAI_LL_ERR_SEG_EOF = 26,
TWAI_LL_ERR_SEG_ACK_DELIM = 27,
TWAI_LL_ERR_SEG_OVRLD_FLAG = 28,
TWAI_LL_ERR_SEG_MAX = 29,
} twai_ll_err_seg_t;
#endif
/* ---------------------------- Mode Register ------------------------------- */
/**
* @brief Enter reset mode
*
* When in reset mode, the TWAI controller is effectively disconnected from the
* TWAI bus and will not participate in any bus activates. Reset mode is required
* in order to write the majority of configuration registers.
*
* @param hw Start address of the TWAI registers
*
* @note Reset mode is automatically entered on BUS OFF condition
*/
static inline void twai_ll_enter_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 1;
}
/**
* @brief Exit reset mode
*
* When not in reset mode, the TWAI controller will take part in bus activities
* (e.g., send/receive/acknowledge messages and error frames) depending on the
* operating mode.
*
* @param hw Start address of the TWAI registers
*
* @note Reset mode must be exit to initiate BUS OFF recovery
*/
static inline void twai_ll_exit_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 0;
}
/**
* @brief Check if in reset mode
* @param hw Start address of the TWAI registers
* @return true if in reset mode
*/
static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw)
{
return hw->mode_reg.rm;
}
/**
* @brief Set operating mode of TWAI controller
*
* @param hw Start address of the TWAI registers
* @param mode Operating mode
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_mode(twai_dev_t *hw, twai_mode_t mode)
{
if (mode == TWAI_MODE_NORMAL) { //Normal Operating mode
hw->mode_reg.lom = 0;
hw->mode_reg.stm = 0;
} else if (mode == TWAI_MODE_NO_ACK) { //Self Test Mode (No Ack)
hw->mode_reg.lom = 0;
hw->mode_reg.stm = 1;
} else if (mode == TWAI_MODE_LISTEN_ONLY) { //Listen Only Mode
hw->mode_reg.lom = 1;
hw->mode_reg.stm = 0;
}
}
/* --------------------------- Command Register ----------------------------- */
/**
* @brief Set TX command
*
* Setting the TX command will cause the TWAI controller to attempt to transmit
* the frame stored in the TX buffer. The TX buffer will be occupied (i.e.,
* locked) until TX completes.
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
{
hw->command_reg.tr = 1;
}
/**
* @brief Set single shot TX command
*
* Similar to setting TX command, but the TWAI controller will not automatically
* retry transmission upon an error (e.g., due to an acknowledgement error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x03; //Writing to TR and AT simultaneously
}
/**
* @brief Aborts TX
*
* Frames awaiting TX will be aborted. Frames already being TX are not aborted.
* Transmission Complete Status bit is automatically set to 1.
* Similar to setting TX command, but the TWAI controller will not automatically
* retry transmission upon an error (e.g., due to acknowledge error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw)
{
hw->command_reg.at = 1;
}
/**
* @brief Release RX buffer
*
* Rotates RX buffer to the next frame in the RX FIFO.
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw)
{
hw->command_reg.rrb = 1;
}
/**
* @brief Clear data overrun
*
* Clears the data overrun status bit
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw)
{
hw->command_reg.cdo = 1;
}
/**
* @brief Set self reception single shot command
*
* Similar to setting TX command, but the TWAI controller also simultaneously
* receive the transmitted frame and is generally used for self testing
* purposes. The TWAI controller will not ACK the received message, so consider
* using the NO_ACK operating mode.
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
{
hw->command_reg.srr = 1;
}
/**
* @brief Set self reception request command
*
* Similar to setting the self reception request, but the TWAI controller will
* not automatically retry transmission upon an error (e.g., due to and
* acknowledgement error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x12;
}
/* --------------------------- Status Register ------------------------------ */
/**
* @brief Get all status bits
*
* @param hw Start address of the TWAI registers
* @return Status bits
*/
static inline uint32_t twai_ll_get_status(twai_dev_t *hw)
{
return hw->status_reg.val;
}
/**
* @brief Check if RX FIFO overrun status bit is set
*
* @param hw Start address of the TWAI registers
* @return Overrun status bit
*/
static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw)
{
return hw->status_reg.dos;
}
/**
* @brief Check if previously TX was successful
*
* @param hw Start address of the TWAI registers
* @return Whether previous TX was successful
*/
static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
{
return hw->status_reg.tcs;
}
/* -------------------------- Interrupt Register ---------------------------- */
/**
* @brief Get currently set interrupts
*
* Reading the interrupt registers will automatically clear all interrupts
* except for the Receive Interrupt.
*
* @param hw Start address of the TWAI registers
* @return Bit mask of set interrupts
*/
static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
{
return hw->interrupt_reg.val;
}
/* ----------------------- Interrupt Enable Register ------------------------ */
/**
* @brief Set which interrupts are enabled
*
* @param hw Start address of the TWAI registers
* @param Bit mask of interrupts to enable
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
{
#if SOC_TWAI_BRP_DIV_SUPPORTED
//ESP32 Rev 2 or later has brp div field. Need to mask it out
hw->interrupt_enable_reg.val = (hw->interrupt_enable_reg.val & 0x10) | intr_mask;
#else
hw->interrupt_enable_reg.val = intr_mask;
#endif
}
/* ------------------------ Bus Timing Registers --------------------------- */
/**
* @brief Set bus timing
*
* @param hw Start address of the TWAI registers
* @param brp Baud Rate Prescaler
* @param sjw Synchronization Jump Width
* @param tseg1 Timing Segment 1
* @param tseg2 Timing Segment 2
* @param triple_sampling Triple Sampling enable/disable
*
* @note Must be called in reset mode
* @note ESP32 rev 2 or later can support a x2 brp by setting a brp_div bit,
* allowing the brp to go from a maximum of 128 to 256.
*/
static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling)
{
#if SOC_TWAI_BRP_DIV_SUPPORTED
if (brp > SOC_TWAI_BRP_DIV_THRESH) {
//Need to set brp_div bit
hw->interrupt_enable_reg.brp_div = 1;
brp /= 2;
} else {
hw->interrupt_enable_reg.brp_div = 0;
}
#endif
hw->bus_timing_0_reg.brp = (brp / 2) - 1;
hw->bus_timing_0_reg.sjw = sjw - 1;
hw->bus_timing_1_reg.tseg1 = tseg1 - 1;
hw->bus_timing_1_reg.tseg2 = tseg2 - 1;
hw->bus_timing_1_reg.sam = triple_sampling;
}
/* ----------------------------- ALC Register ------------------------------- */
/**
* @brief Clear Arbitration Lost Capture Register
*
* Reading the ALC register rearms the Arbitration Lost Interrupt
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
{
(void)hw->arbitration_lost_captue_reg.val;
}
/* ----------------------------- ECC Register ------------------------------- */
/**
* @brief Clear Error Code Capture register
*
* Reading the ECC register rearms the Bus Error Interrupt
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw)
{
(void)hw->error_code_capture_reg.val;
}
#ifdef CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID
static inline void twai_ll_parse_err_code_cap(twai_dev_t *hw,
twai_ll_err_type_t *type,
twai_ll_err_dir_t *dir,
twai_ll_err_seg_t *seg)
{
uint32_t ecc = hw->error_code_capture_reg.val;
*type = (twai_ll_err_type_t) ((ecc >> 6) & 0x3);
*dir = (twai_ll_err_dir_t) ((ecc >> 5) & 0x1);
*seg = (twai_ll_err_seg_t) (ecc & 0x1F);
}
#endif
/* ----------------------------- EWL Register ------------------------------- */
/**
* @brief Set Error Warning Limit
*
* @param hw Start address of the TWAI registers
* @param ewl Error Warning Limit
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_err_warn_lim(twai_dev_t *hw, uint32_t ewl)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->error_warning_limit_reg, ewl, ewl);
}
/**
* @brief Get Error Warning Limit
*
* @param hw Start address of the TWAI registers
* @return Error Warning Limit
*/
static inline uint32_t twai_ll_get_err_warn_lim(twai_dev_t *hw)
{
return hw->error_warning_limit_reg.val;
}
/* ------------------------ RX Error Count Register ------------------------- */
/**
* @brief Get RX Error Counter
*
* @param hw Start address of the TWAI registers
* @return REC value
*
* @note REC is not frozen in reset mode. Listen only mode will freeze it. A BUS
* OFF condition automatically sets the REC to 0.
*/
static inline uint32_t twai_ll_get_rec(twai_dev_t *hw)
{
return hw->rx_error_counter_reg.val;
}
/**
* @brief Set RX Error Counter
*
* @param hw Start address of the TWAI registers
* @param rec REC value
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_rec(twai_dev_t *hw, uint32_t rec)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->rx_error_counter_reg, rxerr, rec);
}
/* ------------------------ TX Error Count Register ------------------------- */
/**
* @brief Get TX Error Counter
*
* @param hw Start address of the TWAI registers
* @return TEC value
*
* @note A BUS OFF condition will automatically set this to 128
*/
static inline uint32_t twai_ll_get_tec(twai_dev_t *hw)
{
return hw->tx_error_counter_reg.val;
}
/**
* @brief Set TX Error Counter
*
* @param hw Start address of the TWAI registers
* @param tec TEC value
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_tec(twai_dev_t *hw, uint32_t tec)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tx_error_counter_reg, txerr, tec);
}
/* ---------------------- Acceptance Filter Registers ----------------------- */
/**
* @brief Set Acceptance Filter
* @param hw Start address of the TWAI registers
* @param code Acceptance Code
* @param mask Acceptance Mask
* @param single_filter Whether to enable single filter mode
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_acc_filter(twai_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
{
uint32_t code_swapped = HAL_SWAP32(code);
uint32_t mask_swapped = HAL_SWAP32(mask);
for (int i = 0; i < 4; i++) {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.acr[i], byte, ((code_swapped >> (i * 8)) & 0xFF));
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.amr[i], byte, ((mask_swapped >> (i * 8)) & 0xFF));
}
hw->mode_reg.afm = single_filter;
}
/* ------------------------- TX/RX Buffer Registers ------------------------- */
/**
* @brief Copy a formatted TWAI frame into TX buffer for transmission
*
* @param hw Start address of the TWAI registers
* @param tx_frame Pointer to formatted frame
*
* @note Call twai_ll_format_frame_buffer() to format a frame
*/
static inline void twai_ll_set_tx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *tx_frame)
{
//Copy formatted frame into TX buffer
for (int i = 0; i < 13; i++) {
hw->tx_rx_buffer[i].val = tx_frame->bytes[i];
}
}
/**
* @brief Copy a received frame from the RX buffer for parsing
*
* @param hw Start address of the TWAI registers
* @param rx_frame Pointer to store formatted frame
*
* @note Call twai_ll_prase_frame_buffer() to parse the formatted frame
*/
static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *rx_frame)
{
//Copy RX buffer registers into frame
for (int i = 0; i < 13; i++) {
rx_frame->bytes[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->tx_rx_buffer[i], byte);
}
}
/**
* @brief Format contents of a TWAI frame into layout of TX Buffer
*
* This function encodes a message into a frame structure. The frame structure
* has an identical layout to the TX buffer, allowing the frame structure to be
* directly copied into TX buffer.
*
* @param[in] 11bit or 29bit ID
* @param[in] dlc Data length code
* @param[in] data Pointer to an 8 byte array containing data. NULL if no data
* @param[in] format Type of TWAI frame
* @param[in] single_shot Frame will not be retransmitted on failure
* @param[in] self_rx Frame will also be simultaneously received
* @param[out] tx_frame Pointer to store formatted frame
*/
static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const uint8_t *data,
uint32_t flags, twai_ll_frame_buffer_t *tx_frame)
{
bool is_extd = flags & TWAI_MSG_FLAG_EXTD;
bool is_rtr = flags & TWAI_MSG_FLAG_RTR;
//Set frame information
tx_frame->dlc = dlc;
tx_frame->frame_format = is_extd;
tx_frame->rtr = is_rtr;
tx_frame->self_reception = (flags & TWAI_MSG_FLAG_SELF) ? 1 : 0;
tx_frame->single_shot = (flags & TWAI_MSG_FLAG_SS) ? 1 : 0;
//Set ID. The ID registers are big endian and left aligned, therefore a bswap will be required
if (is_extd) {
uint32_t id_temp = HAL_SWAP32((id & TWAI_EXTD_ID_MASK) << 3); //((id << 3) >> 8*(3-i))
for (int i = 0; i < 4; i++) {
tx_frame->extended.id[i] = (id_temp >> (8 * i)) & 0xFF;
}
} else {
uint32_t id_temp = HAL_SWAP16((id & TWAI_STD_ID_MASK) << 5); //((id << 5) >> 8*(1-i))
for (int i = 0; i < 2; i++) {
tx_frame->standard.id[i] = (id_temp >> (8 * i)) & 0xFF;
}
}
uint8_t *data_buffer = (is_extd) ? tx_frame->extended.data : tx_frame->standard.data;
if (!is_rtr) { //Only copy data if the frame is a data frame (i.e not RTR)
for (int i = 0; (i < dlc) && (i < TWAI_FRAME_MAX_DLC); i++) {
data_buffer[i] = data[i];
}
}
}
/**
* @brief Parse formatted TWAI frame (RX Buffer Layout) into its constituent contents
*
* @param[in] rx_frame Pointer to formatted frame
* @param[out] id 11 or 29bit ID
* @param[out] dlc Data length code
* @param[out] data Data. Left over bytes set to 0.
* @param[out] format Type of TWAI frame
*/
static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
uint8_t *data, uint32_t *flags)
{
//Copy frame information
*dlc = rx_frame->dlc;
uint32_t flags_temp = 0;
flags_temp |= (rx_frame->frame_format) ? TWAI_MSG_FLAG_EXTD : 0;
flags_temp |= (rx_frame->rtr) ? TWAI_MSG_FLAG_RTR : 0;
flags_temp |= (rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_MSG_FLAG_DLC_NON_COMP : 0;
*flags = flags_temp;
//Copy ID. The ID registers are big endian and left aligned, therefore a bswap will be required
if (rx_frame->frame_format) {
uint32_t id_temp = 0;
for (int i = 0; i < 4; i++) {
id_temp |= rx_frame->extended.id[i] << (8 * i);
}
id_temp = HAL_SWAP32(id_temp) >> 3; //((byte[i] << 8*(3-i)) >> 3)
*id = id_temp & TWAI_EXTD_ID_MASK;
} else {
uint32_t id_temp = 0;
for (int i = 0; i < 2; i++) {
id_temp |= rx_frame->standard.id[i] << (8 * i);
}
id_temp = HAL_SWAP16(id_temp) >> 5; //((byte[i] << 8*(1-i)) >> 5)
*id = id_temp & TWAI_STD_ID_MASK;
}
uint8_t *data_buffer = (rx_frame->frame_format) ? rx_frame->extended.data : rx_frame->standard.data;
//Only copy data if the frame is a data frame (i.e. not a remote frame)
int data_length = (rx_frame->rtr) ? 0 : ((rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_FRAME_MAX_DLC : rx_frame->dlc);
for (int i = 0; i < data_length; i++) {
data[i] = data_buffer[i];
}
//Set remaining bytes of data to 0
for (int i = data_length; i < TWAI_FRAME_MAX_DLC; i++) {
data[i] = 0;
}
}
/* ----------------------- RX Message Count Register ------------------------ */
/**
* @brief Get RX Message Counter
*
* @param hw Start address of the TWAI registers
* @return RX Message Counter
*/
static inline uint32_t twai_ll_get_rx_msg_count(twai_dev_t *hw)
{
return hw->rx_message_counter_reg.val;
}
/* ------------------------- Clock Divider Register ------------------------- */
/**
* @brief Set CLKOUT Divider and enable/disable
*
* Configure CLKOUT. CLKOUT is a pre-scaled version of APB CLK. Divider can be
* 1, or any even number from 2 to 14. Set the divider to 0 to disable CLKOUT.
*
* @param hw Start address of the TWAI registers
* @param divider Divider for CLKOUT. Set to 0 to disable CLKOUT
*/
static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider)
{
if (divider >= 2 && divider <= 14) {
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = (divider / 2) - 1;
} else if (divider == 1) {
//Setting the divider reg to max value (7) means a divider of 1
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = 7;
} else {
hw->clock_divider_reg.co = 1;
hw->clock_divider_reg.cd = 0;
}
}
/**
* @brief Set register address mapping to extended mode
*
* Extended mode register address mapping consists of more registers and extra
* features.
*
* @param hw Start address of the TWAI registers
*
* @note Must be called before setting any configuration
* @note Must be called in reset mode
*/
static inline void twai_ll_enable_extended_reg_layout(twai_dev_t *hw)
{
hw->clock_divider_reg.cm = 1;
}
/* ------------------------- Register Save/Restore -------------------------- */
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
/**
* @brief Saves the current values of the TWAI controller's registers
*
* This function saves the current values of the some of the TWAI controller's
* registers in preparation for a hardware reset of the controller.
*
* @param hw Start address of the TWAI registers
* @param reg_save Pointer to structure to store register values
* @note Must be called in reset mode so that config registers become accessible.
* @note Some registers are cleared on entering reset mode so must be saved
* separate from this function.
*/
static inline void twai_ll_save_reg(twai_dev_t *hw, twai_ll_reg_save_t *reg_save)
{
reg_save->mode_reg = (uint8_t) hw->mode_reg.val;
reg_save->interrupt_enable_reg = (uint8_t) hw->interrupt_enable_reg.val;
reg_save->bus_timing_0_reg = (uint8_t) hw->bus_timing_0_reg.val;
reg_save->bus_timing_1_reg = (uint8_t) hw->bus_timing_1_reg.val;
reg_save->error_warning_limit_reg = (uint8_t) hw->error_warning_limit_reg.val;
for (int i = 0; i < 4; i++) {
reg_save->acr_reg[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->acceptance_filter.acr[i], byte);
reg_save->amr_reg[i] = HAL_FORCE_READ_U32_REG_FIELD(hw->acceptance_filter.amr[i], byte);
}
reg_save->rx_error_counter_reg = (uint8_t) hw->rx_error_counter_reg.val;
reg_save->tx_error_counter_reg = (uint8_t) hw->tx_error_counter_reg.val;
reg_save->clock_divider_reg = (uint8_t) hw->clock_divider_reg.val;
}
/**
* @brief Restores the previous values of the TWAI controller's registers
*
* This function restores the previous values of some of the TWAI controller's
* registers following a hardware reset of the controller.
*
* @param hw Start address of the TWAI registers
* @param reg_save Pointer to structure to storing register values to restore
* @note Must be called in reset mode so that config registers become accessible
* @note Some registers are read only thus cannot be restored
*/
static inline void twai_ll_restore_reg(twai_dev_t *hw, twai_ll_reg_save_t *reg_save)
{
hw->mode_reg.val = reg_save->mode_reg;
hw->interrupt_enable_reg.val = reg_save->interrupt_enable_reg;
hw->bus_timing_0_reg.val = reg_save->bus_timing_0_reg;
hw->bus_timing_1_reg.val = reg_save->bus_timing_1_reg;
hw->error_warning_limit_reg.val = reg_save->error_warning_limit_reg;
for (int i = 0; i < 4; i++) {
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.acr[i], byte, reg_save->acr_reg[i]);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->acceptance_filter.amr[i], byte, reg_save->amr_reg[i]);
}
hw->rx_error_counter_reg.val = reg_save->rx_error_counter_reg;
hw->tx_error_counter_reg.val = reg_save->tx_error_counter_reg;
hw->clock_divider_reg.val = reg_save->clock_divider_reg;
}
#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,381 @@
/*
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/dma_types.h"
#include "hal/adc_types.h"
#include "hal/adc_ll.h"
#include "esp_err.h"
#if SOC_GDMA_SUPPORTED
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#endif
#if CONFIG_IDF_TARGET_ESP32S2
//ADC utilises SPI3 DMA on ESP32S2
#include "hal/spi_ll.h"
#endif
#if CONFIG_IDF_TARGET_ESP32
//ADC utilises I2S0 DMA on ESP32
#include "hal/i2s_ll.h"
#endif
#if SOC_GDMA_SUPPORTED
#define ADC_HAL_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_HAL_DMA_INTR_MASK SPI_LL_INTR_IN_SUC_EOF
#else //CONFIG_IDF_TARGET_ESP32
#define ADC_HAL_DMA_INTR_MASK BIT(9)
#endif
typedef enum adc_hal_work_mode_t {
ADC_HAL_ULP_MODE,
ADC_HAL_SINGLE_READ_MODE,
ADC_HAL_CONTINUOUS_READ_MODE,
ADC_HAL_PWDET_MODE
} adc_hal_work_mode_t;
/**
* @brief Enum for DMA descriptor status
*/
typedef enum adc_hal_dma_desc_status_t {
ADC_HAL_DMA_DESC_VALID = 0, ///< This DMA descriptor is written by HW already
ADC_HAL_DMA_DESC_WAITING = 1, ///< This DMA descriptor is not written by HW yet
ADC_HAL_DMA_DESC_NULL = 2 ///< This DMA descriptor is NULL
} adc_hal_dma_desc_status_t;
/**
* @brief Configuration of the HAL
*/
typedef struct adc_hal_config_t {
void *dev; ///< DMA peripheral address
uint32_t desc_max_num; ///< Number of the descriptors linked once
uint32_t dma_chan; ///< DMA channel to be used
uint32_t eof_num; ///< Bytes between 2 in_suc_eof interrupts
} adc_hal_config_t;
/**
* @brief Context of the HAL
*/
typedef struct adc_hal_context_t {
/**< this needs to be malloced by the driver layer first */
dma_descriptor_t *rx_desc; ///< DMA descriptors
/**< these will be assigned by hal layer itself */
dma_descriptor_t desc_dummy_head; ///< Dummy DMA descriptor for ``cur_desc_ptr`` to start
dma_descriptor_t *cur_desc_ptr; ///< Pointer to the current descriptor
/**< these need to be configured by `adc_hal_config_t` via driver layer*/
void *dev; ///< DMA address
uint32_t desc_max_num; ///< Number of the descriptors linked once
uint32_t dma_chan; ///< DMA channel to be used
uint32_t eof_num; ///< Words between 2 in_suc_eof interrupts
} adc_hal_context_t;
typedef struct adc_hal_digi_ctrlr_cfg_t {
bool conv_limit_en; //1: adc conversion will stop when `conv_limit_num` reaches. 0: won't stop. NOTE: esp32 should always be set to 1.
uint32_t conv_limit_num; //see `conv_limit_en`
uint32_t adc_pattern_len; //total pattern item number, including ADC1 and ADC2
adc_digi_pattern_config_t *adc_pattern; //pattern item
uint32_t sample_freq_hz; //ADC sample frequency
adc_digi_convert_mode_t conv_mode; //controller work mode
uint32_t bit_width; //output data width
} adc_hal_digi_ctrlr_cfg_t;
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* Set ADC module power management.
*
* @prarm manage Set ADC power status.
*/
#define adc_hal_set_power_manage(manage) adc_ll_set_power_manage(manage)
void adc_hal_set_controller(adc_ll_num_t unit, adc_hal_work_mode_t work_mode);
#if SOC_ADC_ARBITER_SUPPORTED
//No ADC2 controller arbiter on ESP32
/**
* Config ADC2 module arbiter.
* The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority,
* the low priority controller will read the invalid ADC2 data, and the validity of the data can be judged by the flag bit in the data.
*
* @note Only ADC2 support arbiter.
* @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode.
* @note Default priority: Wi-Fi > RTC > Digital;
*
* @param config Refer to ``adc_arbiter_t``.
*/
void adc_hal_arbiter_config(adc_arbiter_t *config);
#endif //#if SOC_ADC_ARBITER_SUPPORTED
/*---------------------------------------------------------------
PWDET(Power detect) controller setting
---------------------------------------------------------------*/
/**
* Set adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @prarm cct Range: 0 ~ 7.
*/
#define adc_hal_pwdet_set_cct(cct) adc_ll_pwdet_set_cct(cct)
/**
* Get adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @return cct Range: 0 ~ 7.
*/
#define adc_hal_pwdet_get_cct() adc_ll_pwdet_get_cct()
/**
* Enable/disable the output of ADCn's internal reference voltage to one of ADC2's channels.
*
* This function routes the internal reference voltage of ADCn to one of
* ADC2's channels. This reference voltage can then be manually measured
* for calibration purposes.
*
* @note ESP32 only supports output of ADC2's internal reference voltage.
* @param[in] adc ADC unit select
* @param[in] channel ADC2 channel number
* @param[in] en Enable/disable the reference voltage output
*/
#define adc_hal_vref_output(adc, channel, en) adc_ll_vref_output(adc, channel, en)
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* ADC module initialization.
*/
void adc_hal_init(void);
/**
* Digital controller deinitialization.
*
* @param hal Context of the HAL
*/
void adc_hal_digi_deinit(adc_hal_context_t *hal);
/**
* @brief Initialize the hal context
*
* @param hal Context of the HAL
* @param config Configuration of the HAL
*/
void adc_hal_context_config(adc_hal_context_t *hal, const adc_hal_config_t *config);
/**
* @brief Initialize the HW
*
* @param hal Context of the HAL
*/
void adc_hal_digi_init(adc_hal_context_t *hal);
/**
* Setting the digital controller.
*
* @param hal Context of the HAL
* @param cfg Pointer to digital controller paramter.
*/
void adc_hal_digi_controller_config(adc_hal_context_t *hal, const adc_hal_digi_ctrlr_cfg_t *cfg);
/**
* @brief Start Conversion
*
* @param hal Context of the HAL
* @param data_buf Pointer to the data buffer, the length should be multiple of ``desc_max_num`` and ``eof_num`` in ``adc_hal_context_t``
*/
void adc_hal_digi_start(adc_hal_context_t *hal, uint8_t *data_buf);
#if !SOC_GDMA_SUPPORTED
/**
* @brief Get the DMA descriptor that Hardware has finished processing.
*
* @param hal Context of the HAL
*
* @return DMA descriptor address
*/
intptr_t adc_hal_get_desc_addr(adc_hal_context_t *hal);
/**
* @brief Check the hardware interrupt event
*
* @param hal Context of the HAL
* @param mask Event mask
*
* @return True: the event is triggered. False: the event is not triggered yet.
*/
bool adc_hal_check_event(adc_hal_context_t *hal, uint32_t mask);
#endif
/**
* @brief Get the ADC reading result
*
* @param hal Context of the HAL
* @param eof_desc_addr The last descriptor that is finished by HW. Should be got from DMA
* @param[out] cur_desc The descriptor with ADC reading result (from the 1st one to the last one (``eof_desc_addr``))
*
* @return See ``adc_hal_dma_desc_status_t``
*/
adc_hal_dma_desc_status_t adc_hal_get_reading_result(adc_hal_context_t *hal, const intptr_t eof_desc_addr, dma_descriptor_t **cur_desc);
/**
* @brief Clear interrupt
*
* @param hal Context of the HAL
* @param mask mask of the interrupt
*/
void adc_hal_digi_clr_intr(adc_hal_context_t *hal, uint32_t mask);
/**
* @brief Enable interrupt
*
* @param hal Context of the HAL
* @param mask mask of the interrupt
*/
void adc_hal_digi_dis_intr(adc_hal_context_t *hal, uint32_t mask);
/**
* @brief Stop conversion
*
* @param hal Context of the HAL
*/
void adc_hal_digi_stop(adc_hal_context_t *hal);
/*---------------------------------------------------------------
ADC Single Read
---------------------------------------------------------------*/
#if SOC_ADC_RTC_CTRL_SUPPORTED
/**
* Set the attenuation of a particular channel on ADCn.
*
* @note For any given channel, this function must be called before the first time conversion.
*
* The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage,
* usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.
*
* When VDD_A is 3.3V:
*
* - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below)
*
* @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured
* bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
*
* @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.
*
* Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges:
*
* - 0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV
* - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV
* - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV
* - 11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @param atten ADC attenuation. See ``adc_atten_t``
*/
#define adc_hal_set_atten(adc_n, channel, atten) adc_ll_set_atten(adc_n, channel, atten)
#else // #if !SOC_ADC_RTC_CTRL_SUPPORTED
/**
* Set the attenuation for ADC to single read
*
* @note All ADC units and channels will share the setting. So PLEASE DO save your attenuations and reset them by calling this API again in your driver
*
* @param adc_n Not used, leave here for chip version compatibility
* @param channel Not used, leave here for chip version compatibility
* @param atten ADC attenuation. See ``adc_atten_t``
*/
#define adc_hal_set_atten(adc_n, channel, atten) adc_ll_onetime_set_atten(atten)
#endif //#if SOC_ADC_RTC_CTRL_SUPPORTED
/**
* Start an ADC conversion and get the converted value.
*
* @note It may be block to wait conversion finish.
*
* @param adc_n ADC unit.
* @param channel ADC channel number.
* @param[out] out_raw ADC converted result
*
* @return
* - ESP_OK: The value is valid.
* - ESP_ERR_INVALID_STATE: The value is invalid.
*/
esp_err_t adc_hal_convert(adc_ll_num_t adc_n, int channel, int *out_raw);
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
/**
* @brief Initialize default parameter for the calibration block.
*
* @param adc_n ADC index numer
*/
void adc_hal_calibration_init(adc_ll_num_t adc_n);
/**
* Set the calibration result (initial data) to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param param the calibration parameter to configure
*/
void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param);
/**
* Calibrate the ADC using internal connections.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param channel adc channel number.
* @param atten The attenuation for the channel
* @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage.
* false: Use IO external voltage as calibration voltage.
*
* @return
* - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set.
*/
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd);
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
/**
* Set adc output data format for RTC controller.
*
* @prarm adc_n ADC unit.
* @prarm bits Output data bits width option.
*/
#define adc_hal_rtc_set_output_format(adc_n, bits) adc_ll_rtc_set_output_format(adc_n, bits)
/**
* ADC module output data invert or not.
*
* @prarm adc_n ADC unit.
*/
#define adc_hal_rtc_output_invert(adc_n, inv_en) adc_ll_rtc_output_invert(adc_n, inv_en)

View File

@@ -0,0 +1,357 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_attr.h"
/**
* @brief ADC unit enumeration.
*
* @note For ADC digital controller (DMA mode), ESP32 doesn't support `ADC_UNIT_2`, `ADC_UNIT_BOTH`, `ADC_UNIT_ALTER`.
*/
typedef enum {
ADC_UNIT_1 = 1, /*!< SAR ADC 1. */
ADC_UNIT_2 = 2, /*!< SAR ADC 2. */
ADC_UNIT_BOTH = 3, /*!< SAR ADC 1 and 2. */
ADC_UNIT_ALTER = 7, /*!< SAR ADC 1 and 2 alternative mode. */
ADC_UNIT_MAX,
} adc_unit_t;
/**
* @brief ADC channels handle. See ``adc1_channel_t``, ``adc2_channel_t``.
*
* @note For ESP32 ADC1, don't use `ADC_CHANNEL_8`, `ADC_CHANNEL_9`. See ``adc1_channel_t``.
*/
typedef enum {
ADC_CHANNEL_0 = 0, /*!< ADC channel */
ADC_CHANNEL_1, /*!< ADC channel */
ADC_CHANNEL_2, /*!< ADC channel */
ADC_CHANNEL_3, /*!< ADC channel */
ADC_CHANNEL_4, /*!< ADC channel */
ADC_CHANNEL_5, /*!< ADC channel */
ADC_CHANNEL_6, /*!< ADC channel */
ADC_CHANNEL_7, /*!< ADC channel */
ADC_CHANNEL_8, /*!< ADC channel */
ADC_CHANNEL_9, /*!< ADC channel */
ADC_CHANNEL_MAX,
} adc_channel_t;
/**
* @brief ADC attenuation parameter. Different parameters determine the range of the ADC. See ``adc1_config_channel_atten``.
*/
typedef enum {
ADC_ATTEN_DB_0 = 0, /*!<No input attenumation, ADC can measure up to approx. 800 mV. */
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB (1.33 x) */
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB (2 x) */
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 11 dB (3.55 x) */
ADC_ATTEN_MAX,
} adc_atten_t;
/**
* @brief ADC resolution setting option.
* @note Only used in single read mode
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32
ADC_WIDTH_BIT_9 = 0, /*!< ADC capture width is 9Bit. */
ADC_WIDTH_BIT_10 = 1, /*!< ADC capture width is 10Bit. */
ADC_WIDTH_BIT_11 = 2, /*!< ADC capture width is 11Bit. */
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_MAX_BITWIDTH == 12
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_MAX_BITWIDTH == 13
ADC_WIDTH_BIT_13 = 4, /*!< ADC capture width is 13Bit. */
#endif
ADC_WIDTH_MAX,
} adc_bits_width_t;
/**
* @brief ADC digital controller (DMA mode) work mode.
*/
typedef enum {
ADC_CONV_SINGLE_UNIT_1 = 1, ///< Only use ADC1 for conversion
ADC_CONV_SINGLE_UNIT_2 = 2, ///< Only use ADC2 for conversion
ADC_CONV_BOTH_UNIT = 3, ///< Use Both ADC1 and ADC2 for conversion simultaneously
ADC_CONV_ALTER_UNIT = 7, ///< Use both ADC1 and ADC2 for conversion by turn. e.g. ADC1 -> ADC2 -> ADC1 -> ADC2 .....
ADC_CONV_UNIT_MAX,
} adc_digi_convert_mode_t;
/**
* @brief ADC digital controller (DMA mode) output data format option.
*/
typedef enum {
ADC_DIGI_FORMAT_12BIT __attribute__((deprecated)), /*!<ADC to DMA data format, [15:12]-channel, [11: 0]-12 bits ADC data (`adc_digi_output_data_t`). Note: For single convert mode. */
ADC_DIGI_FORMAT_11BIT __attribute__((deprecated)), /*!<ADC to DMA data format, [15]-adc unit, [14:11]-channel, [10: 0]-11 bits ADC data (`adc_digi_output_data_t`). Note: For multi or alter convert mode. */
ADC_DIGI_FORMAT_MAX __attribute__((deprecated)),
ADC_DIGI_OUTPUT_FORMAT_TYPE1, ///< See `adc_digi_output_data_t.type1`
ADC_DIGI_OUTPUT_FORMAT_TYPE2, ///< See `adc_digi_output_data_t.type2`
} adc_digi_output_format_t;
/**
* @brief ADC digital controller pattern configuration
*/
typedef struct {
uint8_t atten; ///< Attenuation of this ADC channel
uint8_t channel; ///< ADC channel
uint8_t unit; ///< ADC unit
uint8_t bit_width; ///< ADC output bit width
} adc_digi_pattern_config_t;
/*---------------------------------------------------------------
Output Format
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
* @note ESP32: Only `type1` is valid. ADC2 does not support DMA mode.
* @note ESP32-S2: Member `channel` can be used to judge the validity of the ADC data,
* because the role of the arbiter may get invalid ADC data.
*/
typedef struct {
union {
struct {
uint16_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
uint16_t channel: 4; /*!<ADC channel index info. */
} type1; /*!<ADC type1 */
struct {
uint16_t data: 11; /*!<ADC real output data info. Resolution: 11 bit. */
uint16_t channel: 4; /*!<ADC channel index info. For ESP32-S2:
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint16_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
} type2; /*!<When the configured output format is 11bit. `ADC_DIGI_FORMAT_11BIT` */
uint16_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
*/
typedef struct {
union {
struct {
uint32_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
uint32_t reserved12: 1; /*!<Reserved12. */
uint32_t channel: 3; /*!<ADC channel index info.
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint32_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
uint32_t reserved17_31: 15; /*!<Reserved17. */
} type2; /*!<When the configured output format is 12bit. `ADC_DIGI_FORMAT_11BIT` */
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#elif CONFIG_IDF_TARGET_ESP32S3
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
*/
typedef struct {
union {
struct {
uint32_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
uint32_t reserved12: 1; /*!<Reserved12. */
uint32_t channel: 4; /*!<ADC channel index info.
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint32_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
uint32_t reserved17_31: 14; /*!<Reserved17. */
} type2; /*!<When the configured output format is 12bit. `ADC_DIGI_FORMAT_11BIT` */
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#endif
#if SOC_ADC_ARBITER_SUPPORTED
/*---------------------------------------------------------------
Arbiter
---------------------------------------------------------------*/
/**
* @brief ADC arbiter work mode option.
*
* @note ESP32-S2: Only ADC2 support arbiter.
*/
typedef enum {
ADC_ARB_MODE_SHIELD,/*!<Force shield arbiter, Select the highest priority controller to work. */
ADC_ARB_MODE_FIX, /*!<Fixed priority switch controller mode. */
ADC_ARB_MODE_LOOP, /*!<Loop priority switch controller mode. Each controller has the same priority,
and the arbiter will switch to the next controller after the measurement is completed. */
} adc_arbiter_mode_t;
/**
* @brief ADC arbiter work mode and priority setting.
*
* @note ESP32-S2: Only ADC2 support arbiter.
*/
typedef struct {
adc_arbiter_mode_t mode; /*!<Refer to ``adc_arbiter_mode_t``. Note: only support ADC2. */
uint8_t rtc_pri; /*!<RTC controller priority. Range: 0 ~ 2. */
uint8_t dig_pri; /*!<Digital controller priority. Range: 0 ~ 2. */
uint8_t pwdet_pri; /*!<Wi-Fi controller priority. Range: 0 ~ 2. */
} adc_arbiter_t;
/**
* @brief ADC arbiter default configuration.
*
* @note ESP32S2: Only ADC2 supports (needs) an arbiter.
*/
#define ADC_ARBITER_CONFIG_DEFAULT() { \
.mode = ADC_ARB_MODE_FIX, \
.rtc_pri = 1, \
.dig_pri = 0, \
.pwdet_pri = 2, \
}
#endif //#if SOC_ADC_ARBITER_SUPPORTED
#if SOC_ADC_FILTER_SUPPORTED
/*---------------------------------------------------------------
Filter
---------------------------------------------------------------*/
/**
* @brief ADC digital controller (DMA mode) filter index options.
*
* @note For ESP32-S2, The filter object of the ADC is fixed.
*/
typedef enum {
ADC_DIGI_FILTER_IDX0 = 0, /*!<The filter index 0.
For ESP32-S2, It can only be used to filter all enabled channels of ADC1 unit at the same time. */
ADC_DIGI_FILTER_IDX1, /*!<The filter index 1.
For ESP32-S2, It can only be used to filter all enabled channels of ADC2 unit at the same time. */
ADC_DIGI_FILTER_IDX_MAX
} adc_digi_filter_idx_t;
/**
* @brief ADC digital controller (DMA mode) filter type options.
* Expression: filter_data = (k-1)/k * last_data + new_data / k.
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
ADC_DIGI_FILTER_DIS = -1, /*!< Disable filter */
#endif
ADC_DIGI_FILTER_IIR_2 = 0, /*!<The filter mode is first-order IIR filter. The coefficient is 2. */
ADC_DIGI_FILTER_IIR_4, /*!<The filter mode is first-order IIR filter. The coefficient is 4. */
ADC_DIGI_FILTER_IIR_8, /*!<The filter mode is first-order IIR filter. The coefficient is 8. */
ADC_DIGI_FILTER_IIR_16, /*!<The filter mode is first-order IIR filter. The coefficient is 16. */
ADC_DIGI_FILTER_IIR_64, /*!<The filter mode is first-order IIR filter. The coefficient is 64. */
ADC_DIGI_FILTER_IIR_MAX
} adc_digi_filter_mode_t;
/**
* @brief ADC digital controller (DMA mode) filter configuration.
*
* @note For ESP32-S2, The filter object of the ADC is fixed.
* @note For ESP32-S2, The filter object is always all enabled channels.
*/
typedef struct {
adc_unit_t adc_unit; /*!<Set adc unit number for filter.
For ESP32-S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time. */
adc_channel_t channel; /*!<Set adc channel number for filter.
For ESP32-S2, it's always `ADC_CHANNEL_MAX` */
adc_digi_filter_mode_t mode;/*!<Set adc filter mode for filter. See ``adc_digi_filter_mode_t``. */
} adc_digi_filter_t;
#endif // #if SOC_ADC_FILTER_SUPPORTED
#if SOC_ADC_MONITOR_SUPPORTED
/*---------------------------------------------------------------
Monitor
---------------------------------------------------------------*/
/**
* @brief ADC digital controller (DMA mode) monitor index options.
*
* @note For ESP32-S2, The monitor object of the ADC is fixed.
*/
typedef enum {
ADC_DIGI_MONITOR_IDX0 = 0, /*!<The monitor index 0.
For ESP32-S2, It can only be used to monitor all enabled channels of ADC1 unit at the same time. */
ADC_DIGI_MONITOR_IDX1, /*!<The monitor index 1.
For ESP32-S2, It can only be used to monitor all enabled channels of ADC2 unit at the same time. */
ADC_DIGI_MONITOR_IDX_MAX
} adc_digi_monitor_idx_t;
/**
* @brief Set monitor mode of adc digital controller.
* MONITOR_HIGH:If ADC_OUT > threshold, Generates monitor interrupt.
* MONITOR_LOW: If ADC_OUT < threshold, Generates monitor interrupt.
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
ADC_DIGI_MONITOR_DIS = 0, /*!<Disable monitor. */
ADC_DIGI_MONITOR_EN, /*!<If ADC_OUT < threshold, Generates monitor interrupt. */
/*!<If ADC_OUT > threshold, Generates monitor interrupt. */
#else
ADC_DIGI_MONITOR_HIGH = 0, /*!<If ADC_OUT > threshold, Generates monitor interrupt. */
ADC_DIGI_MONITOR_LOW, /*!<If ADC_OUT < threshold, Generates monitor interrupt. */
#endif
ADC_DIGI_MONITOR_MAX
} adc_digi_monitor_mode_t;
/**
* @brief ADC digital controller (DMA mode) monitor configuration.
*
* @note For ESP32-S2, The monitor object of the ADC is fixed.
* @note For ESP32-S2, The monitor object is always all enabled channels.
*/
typedef struct {
adc_unit_t adc_unit; /*!<Set adc unit number for monitor.
For ESP32-S2, monitor IDX0/IDX1 can only be used to monitor all enabled channels of ADC1/ADC2 unit at the same time. */
adc_channel_t channel; /*!<Set adc channel number for monitor.
For ESP32-S2, it's always `ADC_CHANNEL_MAX` */
adc_digi_monitor_mode_t mode; /*!<Set adc monitor mode. See ``adc_digi_monitor_mode_t``. */
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
uint32_t h_threshold; /*!<Set monitor threshold of adc digital controller. */
uint32_t l_threshold; /*!<Set monitor threshold of adc digital controller. */
#else
uint32_t threshold; /*!<Set monitor threshold of adc digital controller. */
#endif
} adc_digi_monitor_t;
#endif //#if SOC_ADC_MONITOR_SUPPORTED
/*---------------------------------------------------------------
To Be Deprecated TODO: IDF-3610
---------------------------------------------------------------*/
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* @brief ESP32 ADC DMA source selection.
*/
#else
/**
* @brief ESP32 ADC DMA source selection.
*
* @deprecated Not applicable on ESP32-S2 because ESP32-S2 doesn't use I2S DMA.
*/
#endif
typedef enum {
ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */
ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */
ADC_I2S_DATA_SRC_MAX,
} adc_i2s_source_t;
#if CONFIG_IDF_TARGET_ESP32S2
/**
* @brief ADC digital controller (DMA mode) clock system setting.
* Calculation formula: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
*
* @note: The clocks of the DAC digital controller use the ADC digital controller clock divider.
*/
typedef struct {
bool use_apll; /*!<true: use APLL clock; false: use APB clock. */
uint32_t div_num; /*!<Division factor. Range: 0 ~ 255.
Note: When a higher frequency clock is used (the division factor is less than 9),
the ADC reading value will be slightly offset. */
uint32_t div_b; /*!<Division factor. Range: 1 ~ 63. */
uint32_t div_a; /*!<Division factor. Range: 0 ~ 63. */
} adc_digi_clk_t;
#endif

View File

@@ -0,0 +1,157 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "hal/aes_types.h"
#include "hal/aes_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Sets the key used for AES encryption/decryption
*
* @param key pointer to the key
* @param key_bytes number of bytes in key
* @param mode key mode, 0 : decrypt, 1: encrypt
*
* @return uint8_t number of key bytes written to hardware, used for fault injection check
*/
uint8_t aes_hal_setkey(const uint8_t *key, size_t key_bytes, int mode);
/**
* @brief encrypts/decrypts a single block
*
* @param input_block input block, size of AES_BLOCK_BYTES
* @param output_block output block, size of AES_BLOCK_BYTES
*/
void aes_hal_transform_block(const void *input_block, void *output_block);
#if SOC_AES_SUPPORT_DMA
/**
* @brief Inits the AES mode of operation
*
* @param mode mode of operation, e.g. CTR or CBC
*/
void aes_hal_mode_init(esp_aes_mode_t mode);
/**
* @brief Sets the initialization vector for the transform
*
* @note The same IV must never be reused with the same key
*
* @param iv the initialization vector, length = IV_BYTES (16 bytes)
*/
void aes_hal_set_iv(const uint8_t *iv);
/**
* @brief Reads the initialization vector
*
* @param iv initialization vector read from HW, length = IV_BYTES (16 bytes)
*/
void aes_hal_read_iv(uint8_t *iv);
/**
* @brief Busy waits until the AES operation is done
*
* @param output pointer to inlink descriptor
*/
void aes_hal_wait_done(void);
/**
* @brief Starts an already configured AES DMA transform
*
* @param num_blocks Number of blocks to transform
*/
void aes_hal_transform_dma_start(size_t num_blocks);
/**
* @brief Finish up a AES DMA conversion, release DMA
*
*/
void aes_hal_transform_dma_finish(void);
/**
* @brief Enable or disable transform completed interrupt
*
* @param enable true to enable, false to disable.
*/
#define aes_hal_interrupt_enable(enable) aes_ll_interrupt_enable(enable)
/**
* @brief Clears the interrupt
*
*/
#define aes_hal_interrupt_clear() aes_ll_interrupt_clear()
#if SOC_AES_SUPPORT_GCM
/**
* @brief Calculates the Hash sub-key H0 needed to start AES-GCM
*
* @param gcm_hash the Hash sub-key H0 output
*/
void aes_hal_gcm_calc_hash(uint8_t *gcm_hash);
/**
* @brief Initializes the AES hardware for AES-GCM
*
* @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks
* @param num_valid_bit the number of effective bits of incomplete blocks in plaintext/cipertext
*/
void aes_hal_gcm_init(size_t aad_num_blocks, size_t num_valid_bit);
/**
* @brief Starts a AES-GCM transform
*
* @param num_blocks Number of blocks to transform
*/
void aes_hal_transform_dma_gcm_start(size_t num_blocks);
/**
* @brief Sets the J0 value, for more information see the GCM subchapter in the TRM
*
* @note Only affects AES-GCM
*
* @param j0 J0 value
*/
#define aes_hal_gcm_set_j0(j0) aes_ll_gcm_set_j0(j0)
/**
* @brief Read the tag after a AES-GCM transform
*
* @param tag Pointer to where to store the result
* @param tag_length number of bytes to read into tag
*/
void aes_hal_gcm_read_tag(uint8_t *tag, size_t tag_len);
#endif //SOC_AES_SUPPORT_GCM
#endif //SOC_AES_SUPPORT_DMA
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,48 @@
// 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.
#pragma once
/* padlock.c and aesni.c rely on these values! */
#define ESP_AES_ENCRYPT 1
#define ESP_AES_DECRYPT 0
/* DMA AES working modes*/
typedef enum {
ESP_AES_BLOCK_MODE_ECB = 0,
ESP_AES_BLOCK_MODE_CBC,
ESP_AES_BLOCK_MODE_OFB,
ESP_AES_BLOCK_MODE_CTR,
ESP_AES_BLOCK_MODE_CFB8,
ESP_AES_BLOCK_MODE_CFB128,
ESP_AES_BLOCK_MODE_GCM,
ESP_AES_BLOCK_MODE_MAX,
} esp_aes_mode_t;
/* Number of bytes in an AES block */
#define AES_BLOCK_BYTES (16)
/* Number of words in an AES block */
#define AES_BLOCK_WORDS (4)
/* Number of bytes in an IV */
#define IV_BYTES (16)
/* Number of words in an IV */
#define IV_WORDS (4)
/* Number of bytes in a GCM tag block */
#define TAG_BYTES (16)
/* Number of words in a GCM tag block */
#define TAG_WORDS (4)
#define AES_128_KEY_BYTES (128/8)
#define AES_192_KEY_BYTES (192/8)
#define AES_256_KEY_BYTES (256/8)

View File

@@ -0,0 +1,48 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "soc/soc_caps.h"
typedef struct {
uint8_t threshold;
bool enabled;
bool reset_enabled;
bool flash_power_down;
bool rf_power_down;
} brownout_hal_config_t;
void brownout_hal_config(const brownout_hal_config_t *cfg);
void brownout_hal_intr_enable(bool enable);
void brownout_hal_intr_clear(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/cpu_types.h"
#include "hal/cpu_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Return the ID of the core currently executing this code.
*
* @return core id [0..SOC_CPU_CORES_NUM - 1]
*/
#define cpu_hal_get_core_id() cpu_ll_get_core_id()
/**
* Get the current value of the stack pointer.
*
* @return the current stack pointer
*/
#define cpu_hal_get_sp() cpu_ll_get_sp()
/**
* Get the current value of the internal counter that increments
* every processor-clock cycle.
*
* @return cycle count; returns 0 if not supported
*/
#define cpu_hal_get_cycle_count() cpu_ll_get_cycle_count()
/**
* Set the given value into the internal counter that increments
* every processor-clock cycle.
*/
#define cpu_hal_set_cycle_count(val) cpu_ll_set_cycle_count(val)
/**
* Check if some form of debugger is attached to CPU.
*
* @return true debugger is attached
* @return false no debugger is attached/ no support for debuggers
*/
#define cpu_hal_is_debugger_attached() cpu_ll_is_debugger_attached()
/**
* Init HW loop status.
*/
#define cpu_hal_init_hwloop() cpu_ll_init_hwloop()
/**
* Trigger a call to debugger.
*/
#define cpu_hal_break() cpu_ll_break()
/**
* Wait for interrupt.
*/
#define cpu_hal_waiti() cpu_ll_waiti()
#if SOC_CPU_BREAKPOINTS_NUM > 0
/**
* Set and enable breakpoint at an instruction address.
*
* @note Overwrites previously set breakpoint with same breakpoint ID.
*
* @param id breakpoint to set [0..SOC_CPU_BREAKPOINTS_NUM - 1]
* @param addr address to set a breakpoint on
*/
void cpu_hal_set_breakpoint(int id, const void* addr);
/**
* Clear and disable breakpoint.
*
* @param id breakpoint to clear [0..SOC_CPU_BREAKPOINTS_NUM - 1]
*/
void cpu_hal_clear_breakpoint(int id);
#endif // SOC_CPU_BREAKPOINTS_NUM > 0
#if SOC_CPU_WATCHPOINTS_NUM > 0
/**
* Set and enable a watchpoint, specifying the memory range and trigger operation.
*
* @param id watchpoint to set [0..SOC_CPU_WATCHPOINTS_NUM - 1]
* @param addr starting address
* @param size number of bytes from starting address to watch
* @param trigger operation on specified memory range that triggers the watchpoint (read, write, read/write)
*/
void cpu_hal_set_watchpoint(int id, const void* addr, size_t size, watchpoint_trigger_t trigger);
/**
* Clear and disable watchpoint.
*
* @param id watchpoint to clear [0..SOC_CPU_WATCHPOINTS_NUM - 1]
*/
void cpu_hal_clear_watchpoint(int id);
#endif // SOC_CPU_WATCHPOINTS_NUM > 0
/**
* Set exception vector table base address.
*
* @param base address to move the exception vector table to
*/
void cpu_hal_set_vecbase(const void* base);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,21 @@
// 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.
#pragma once
typedef enum {
WATCHPOINT_TRIGGER_ON_RO, // on read
WATCHPOINT_TRIGGER_ON_WO, // on write
WATCHPOINT_TRIGGER_ON_RW // on either read or write
} watchpoint_trigger_t;

View File

@@ -0,0 +1,78 @@
// Copyright 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.
/*******************************************************************************
* 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 "hal/dac_ll.h"
/**
* Power on dac module and start output voltage.
*
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
* @param channel DAC channel num.
*/
#define dac_hal_power_on(channel) dac_ll_power_on(channel)
/**
* Power done dac module and stop output voltage.
*
* @param channel DAC channel num.
*/
#define dac_hal_power_down(channel) dac_ll_power_down(channel)
/**
* Enable/disable the synchronization operation function of ADC1 and DAC.
*
* @note If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage.
*
* @param enable Enable or disable adc and dac synchronization function.
*/
#define dac_hal_rtc_sync_by_adc(enable) dac_ll_rtc_sync_by_adc(enable)
/**
* Output voltage with value (8 bit).
*
* @param channel DAC channel num.
* @param value Output value. Value range: 0 ~ 255.
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
*/
#define dac_hal_update_output_value(channel, value) dac_ll_update_output_value(channel, value)
/**
* Enable cosine wave generator output.
*/
#define dac_hal_cw_generator_enable() dac_ll_cw_generator_enable()
/**
* Disable cosine wave generator output.
*/
#define dac_hal_cw_generator_disable() dac_ll_cw_generator_disable()
/**
* Config the cosine wave generator function in DAC module.
*
* @param cw Configuration.
*/
void dac_hal_cw_generator_config(dac_cw_config_t *cw);
/**
* Enable/disable DAC output data from DMA.
*/
#define dac_hal_digi_enable_dma(enable) dac_ll_digi_enable_dma(enable)

View File

@@ -0,0 +1,67 @@
#pragma once
#include "soc/soc_caps.h"
#include "hal/adc_types.h"
#include "sdkconfig.h"
typedef enum {
DAC_CHANNEL_1 = 0, /*!< DAC channel 1 is GPIO25(ESP32) / GPIO17(ESP32S2) */
DAC_CHANNEL_2 = 1, /*!< DAC channel 2 is GPIO26(ESP32) / GPIO18(ESP32S2) */
DAC_CHANNEL_MAX,
} dac_channel_t;
/**
* @brief The multiple of the amplitude of the cosine wave generator. The max amplitude is VDD3P3_RTC.
*/
typedef enum {
DAC_CW_SCALE_1 = 0x0, /*!< 1/1. Default. */
DAC_CW_SCALE_2 = 0x1, /*!< 1/2. */
DAC_CW_SCALE_4 = 0x2, /*!< 1/4. */
DAC_CW_SCALE_8 = 0x3, /*!< 1/8. */
} dac_cw_scale_t;
/**
* @brief Set the phase of the cosine wave generator output.
*/
typedef enum {
DAC_CW_PHASE_0 = 0x2, /*!< Phase shift +0° */
DAC_CW_PHASE_180 = 0x3, /*!< Phase shift +180° */
} dac_cw_phase_t;
/**
* @brief Config the cosine wave generator function in DAC module.
*/
typedef struct {
dac_channel_t en_ch; /*!< Enable the cosine wave generator of DAC channel. */
dac_cw_scale_t scale; /*!< Set the amplitude of the cosine wave generator output. */
dac_cw_phase_t phase; /*!< Set the phase of the cosine wave generator output. */
uint32_t freq; /*!< Set frequency of cosine wave generator output. Range: 130(130Hz) ~ 55000(100KHz). */
int8_t offset; /*!< Set the voltage value of the DC component of the cosine wave generator output.
Note: Unreasonable settings can cause waveform to be oversaturated. Range: -128 ~ 127. */
} dac_cw_config_t;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/**
* @brief DAC digital controller (DMA mode) work mode.
*/
typedef enum {
DAC_CONV_NORMAL, /*!< The data in the DMA buffer is simultaneously output to the enable channel of the DAC. */
DAC_CONV_ALTER, /*!< The data in the DMA buffer is alternately output to the enable channel of the DAC. */
DAC_CONV_MAX
} dac_digi_convert_mode_t;
/**
* @brief DAC digital controller (DMA mode) configuration parameters.
*/
typedef struct {
dac_digi_convert_mode_t mode; /*!<DAC digital controller (DMA mode) work mode. See ``dac_digi_convert_mode_t``. */
uint32_t interval; /*!<The number of interval clock cycles for the DAC digital controller to output voltage.
The unit is the divided clock. Range: 1 ~ 4095.
Expression: `dac_output_freq` = `controller_clk` / interval. Refer to ``adc_digi_clk_t``.
Note: The sampling rate of each channel is also related to the conversion mode (See ``dac_digi_convert_mode_t``) and pattern table settings. */
adc_digi_clk_t dig_clk; /*!<DAC digital controller clock divider settings. Refer to ``adc_digi_clk_t``.
Note: The clocks of the DAC digital controller use the ADC digital controller clock divider. */
} dac_digi_config_t;
#endif //CONFIG_IDF_TARGET_ESP32S2

View File

@@ -0,0 +1,49 @@
// 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.
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of DMA descriptor
*
*/
typedef struct dma_descriptor_s {
struct {
uint32_t size : 12; /*!< Buffer size */
uint32_t length : 12; /*!< Number of valid bytes in the buffer */
uint32_t reversed24_27 : 4; /*!< Reserved */
uint32_t err_eof : 1; /*!< Whether the received buffer contains error */
uint32_t reserved29 : 1; /*!< Reserved */
uint32_t suc_eof : 1; /*!< Whether the descriptor is the last one in the link */
uint32_t owner : 1; /*!< Who is allowed to access the buffer that this descriptor points to */
} dw0; /*!< Descriptor Word 0 */
void *buffer; /*!< Pointer to the buffer */
struct dma_descriptor_s *next; /*!< Pointer to the next descriptor (set to NULL if the descriptor is the last one, e.g. suc_eof=1) */
} dma_descriptor_t;
_Static_assert(sizeof(dma_descriptor_t) == 12, "dma_descriptor_t should occupy 12 bytes in memory");
#define DMA_DESCRIPTOR_BUFFER_OWNER_CPU (0) /*!< DMA buffer is allowed to be accessed by CPU */
#define DMA_DESCRIPTOR_BUFFER_OWNER_DMA (1) /*!< DMA buffer is allowed to be accessed by DMA engine */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,107 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#if CONFIG_IDF_TARGET_ESP32
#error "ESP32 doesn't have a DS peripheral"
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The result when checking whether the key to decrypt the RSA parameters is ready.
*/
typedef enum {
DS_KEY_INPUT_OK = 0, /**< The decryption key is ready. */
DS_NO_KEY_INPUT, /**< Dependent peripheral providing key hasn't been activated. */
DS_OTHER_WRONG, /**< Dependent peripheral running but problem receiving the key. */
} ds_key_check_t;
typedef enum {
DS_SIGNATURE_OK = 0, /**< Signature is valid and can be read. */
DS_SIGNATURE_PADDING_FAIL = 1, /**< Padding invalid, signature can be read if user wants it. */
DS_SIGNATURE_MD_FAIL = 2, /**< Message digest check failed, signature invalid. */
DS_SIGNATURE_PADDING_AND_MD_FAIL = 3, /**< Both padding and MD check failed. */
} ds_signature_check_t;
/**
* @brief Start the whole signing process after the input key is ready.
*
* Call this before using any of the functions below. The input key is ready must be ready at this point.
*/
void ds_hal_start(void);
/**
* @brief Finish the whole signing process. Call this after the signature is read or in case of an error.
*/
void ds_hal_finish(void);
/**
* @brief Write the initialization vector.
*/
void ds_hal_configure_iv(const uint32_t *iv);
/**
* @brief Write the message which should be signed.
*
* @param msg Pointer to the message.
* @param size Length of signature result in bytes. It is the RSA signature length in bytes.
*/
void ds_hal_write_message(const uint8_t *msg, size_t size);
/**
* @brief Write the encrypted private key parameters.
*/
void ds_hal_write_private_key_params(const uint8_t *block);
/**
* @brief Begin signing procedure.
*/
void ds_hal_start_sign(void);
/**
* @brief Check whether the hardware is busy with an operation.
*
* @return True if the hardware has finished the signing procedure, otherwise false.
*/
bool ds_hal_busy(void);
/**
* @brief Check and read the signature from the hardware.
*
* @return
* - DS_SIGNATURE_OK if no issue is detected with the signature.
* - DS_SIGNATURE_PADDING_FAIL if the padding of the private key parameters is wrong.
* - DS_SIGNATURE_MD_FAIL if the message digest check failed. This means that the message digest calculated using
* the private key parameters fails, i.e., the integrity of the private key parameters is not protected.
* - DS_SIGNATURE_PADDING_AND_MD_FAIL if both padding and message digest check fail.
*/
ds_signature_check_t ds_hal_read_result(uint8_t *result, size_t size);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,251 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "hal/eth_types.h"
#include "soc/emac_dma_struct.h"
#include "soc/emac_mac_struct.h"
#include "soc/emac_ext_struct.h"
/**
* @brief Ethernet DMA TX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t Deferred : 1; /*!< MAC defers before transmission */
uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */
uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */
uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */
uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */
uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */
uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */
uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */
uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */
uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */
uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */
uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */
uint32_t ErrSummary : 1; /*!< Error Summary */
uint32_t IPHeadErr : 1; /*!< IP Header Error */
uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */
uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */
uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */
uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */
uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */
uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */
uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */
uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */
uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */
uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */
uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} TDES0;
union {
struct {
uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */
uint32_t Reserved : 3; /*!< Reserved */
uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */
uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */
};
uint32_t Value;
} TDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
uint32_t Reserved1; /*!< Reserved */
uint32_t Reserved2; /*!< Reserved */
uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */
uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */
} eth_dma_tx_descriptor_t;
#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */
#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */
_Static_assert(sizeof(eth_dma_tx_descriptor_t) == 32, "eth_dma_tx_descriptor_t should occupy 32 bytes in memory");
/**
* @brief Ethernet DMA RX Descriptor
*
*/
typedef struct {
volatile union {
struct {
uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */
uint32_t CRCErr : 1; /*!< CRC error occurred on frame */
uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */
uint32_t ReceiveErr : 1; /*!< Receive error */
uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */
uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */
uint32_t LateCollision : 1; /*!< Late collision occurred during reception */
uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */
uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */
uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */
uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */
uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */
uint32_t LengthErr : 1; /*!< Frame size not matching with length field */
uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */
uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */
uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */
uint32_t FrameLength : 14; /*!< Byte length of received frame */
uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
};
uint32_t Value;
} RDES0;
union {
struct {
uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */
uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */
uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */
uint32_t Reserved : 2; /*!< Reserved */
uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */
};
uint32_t Value;
} RDES1;
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
volatile union {
struct {
uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */
uint32_t IPHeadErr : 1; /*!< IP header error */
uint32_t IPPayloadErr : 1; /*!< IP payload error */
uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */
uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */
uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */
uint32_t MessageType : 4; /*!< PTP Message Type */
uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */
uint32_t PTPVersion : 1; /*!< Version of PTP protocol */
uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */
uint32_t Reserved1 : 1; /*!< Reserved */
uint32_t AVPacketReceived : 1; /*!< AV packet is received */
uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */
uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */
uint32_t Reserved2 : 3; /*!< Reserved */
uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */
uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */
uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */
uint32_t Reserved3 : 4; /*!< Reserved */
};
uint32_t Value;
} ExtendedStatus;
uint32_t Reserved; /*!< Reserved */
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
} eth_dma_rx_descriptor_t;
_Static_assert(sizeof(eth_dma_rx_descriptor_t) == 32, "eth_dma_rx_descriptor_t should occupy 32 bytes in memory");
typedef struct {
emac_mac_dev_t *mac_regs;
emac_dma_dev_t *dma_regs;
emac_ext_dev_t *ext_regs;
uint8_t **rx_buf;
uint8_t **tx_buf;
void *descriptors;
eth_dma_rx_descriptor_t *rx_desc;
eth_dma_tx_descriptor_t *tx_desc;
} emac_hal_context_t;
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
uint8_t **rx_buf, uint8_t **tx_buf);
void emac_hal_iomux_init_mii(void);
void emac_hal_iomux_init_rmii(void);
void emac_hal_iomux_rmii_clk_input(void);
void emac_hal_iomux_rmii_clk_ouput(int num);
void emac_hal_iomux_init_tx_er(void);
void emac_hal_iomux_init_rx_er(void);
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
void emac_hal_reset(emac_hal_context_t *hal);
bool emac_hal_is_reset_done(emac_hal_context_t *hal);
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq);
void emac_hal_init_mac_default(emac_hal_context_t *hal);
void emac_hal_init_dma_default(emac_hal_context_t *hal);
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed);
void emac_hal_set_duplex(emac_hal_context_t *hal, eth_duplex_t duplex);
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable);
/**
* @brief Send MAC-CTRL frames to peer (EtherType=0x8808, opcode=0x0001, dest_addr=MAC-specific-ctrl-proto-01 (01:80:c2:00:00:01))
*/
void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable);
bool emac_hal_is_mii_busy(emac_hal_context_t *hal);
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write);
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value);
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal);
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr);
/**
* @brief Starts EMAC Transmission & Reception
*
* @param hal EMAC HAL context infostructure
*/
void emac_hal_start(emac_hal_context_t *hal);
/**
* @brief Stops EMAC Transmission & Reception
*
* @param hal EMAC HAL context infostructure
* @return
* - ESP_OK: succeed
* - ESP_ERR_INVALID_STATE: previous frame transmission/reception is not completed. When this error occurs,
* wait and reapeat the EMAC stop again.
*/
esp_err_t emac_hal_stop(emac_hal_context_t *hal);
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc);
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable);
uint32_t emac_hal_get_intr_enable_status(emac_hal_context_t *hal);
uint32_t emac_hal_get_intr_status(emac_hal_context_t *hal);
void emac_hal_clear_corresponding_intr(emac_hal_context_t *hal, uint32_t bits);
void emac_hal_clear_all_intr(emac_hal_context_t *hal);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,48 @@
// 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.
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Possible errors returned from esp flash internal functions, these error codes
* should be consistent with esp_err_t codes. But in order to make the source
* files less dependent to esp_err_t, they use the error codes defined in this
* replacable header. This header should ensure the consistency to esp_err_t.
*/
enum {
/* These codes should be consistent with esp_err_t errors. However, error codes with the same values are not
* allowed in ESP-IDF. This is a workaround in order to not introduce a dependency between the "soc" and
* "esp_common" components. The disadvantage is that the output of esp_err_to_name(ESP_ERR_FLASH_SIZE_NOT_MATCH)
* will be ESP_ERR_INVALID_SIZE. */
ESP_ERR_FLASH_SIZE_NOT_MATCH = ESP_ERR_INVALID_SIZE, ///< The chip doesn't have enough space for the current partition table
ESP_ERR_FLASH_NO_RESPONSE = ESP_ERR_INVALID_RESPONSE, ///< Chip did not respond to the command, or timed out.
};
//The ROM code has already taken 1 and 2, to avoid possible conflicts, start from 3.
#define ESP_ERR_FLASH_NOT_INITIALISED (ESP_ERR_FLASH_BASE+3) ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init().
#define ESP_ERR_FLASH_UNSUPPORTED_HOST (ESP_ERR_FLASH_BASE+4) ///< Requested operation isn't supported via this host SPI bus (chip->spi field).
#define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip.
#define ESP_ERR_FLASH_PROTECTED (ESP_ERR_FLASH_BASE+6) ///< Write operation failed due to chip's write protection being enabled.
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,65 @@
// Copyright 2021 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.
#pragma once
/**
* @brief Ethernet frame CRC length
*
*/
#define ETH_CRC_LEN (4)
/**
* @brief Ethernet interface
*
*/
typedef enum {
EMAC_DATA_INTERFACE_RMII, /*!< Reduced Media Independent Interface */
EMAC_DATA_INTERFACE_MII, /*!< Media Independent Interface */
} eth_data_interface_t;
/**
* @brief Ethernet link status
*
*/
typedef enum {
ETH_LINK_UP, /*!< Ethernet link is up */
ETH_LINK_DOWN /*!< Ethernet link is down */
} eth_link_t;
/**
* @brief Ethernet speed
*
*/
typedef enum {
ETH_SPEED_10M, /*!< Ethernet speed is 10Mbps */
ETH_SPEED_100M, /*!< Ethernet speed is 100Mbps */
ETH_SPEED_MAX /*!< Max speed mode (for checking purpose) */
} eth_speed_t;
/**
* @brief Ethernet duplex mode
*
*/
typedef enum {
ETH_DUPLEX_HALF, /*!< Ethernet is in half duplex */
ETH_DUPLEX_FULL, /*!< Ethernet is in full duplex */
} eth_duplex_t;
/**
* @brief Ethernet Checksum
*/
typedef enum {
ETH_CHECKSUM_SW, /*!< Ethernet checksum calculate by software */
ETH_CHECKSUM_HW /*!< Ethernet checksum calculate by hardware */
} eth_checksum_t;

View File

@@ -0,0 +1,37 @@
// 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.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in soc/README.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/gdma_struct.h"
typedef struct {
gdma_dev_t *dev;
} gdma_hal_context_t;
void gdma_hal_init(gdma_hal_context_t *hal, int group_id);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,479 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for GPIO
#pragma once
#include "soc/gpio_periph.h"
#include "soc/soc_caps.h"
#include "hal/gpio_ll.h"
#include "hal/gpio_types.h"
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
#include "soc/rtc_io_reg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Get GPIO hardware instance with giving gpio num
#define GPIO_HAL_GET_HW(num) GPIO_LL_GET_HW(num)
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
gpio_dev_t *dev;
uint32_t version;
} gpio_hal_context_t;
/**
* @brief Enable pull-up on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_pullup_en(hal, gpio_num) gpio_ll_pullup_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-up on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_pullup_dis(hal, gpio_num) gpio_ll_pullup_dis((hal)->dev, gpio_num)
/**
* @brief Enable pull-down on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_pulldown_en(hal, gpio_num) gpio_ll_pulldown_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-down on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_pulldown_dis(hal, gpio_num) gpio_ll_pulldown_dis((hal)->dev, gpio_num)
/**
* @brief GPIO set interrupt trigger type
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param intr_type Interrupt type, select from gpio_int_type_t
*/
#define gpio_hal_set_intr_type(hal, gpio_num, intr_type) gpio_ll_set_intr_type((hal)->dev, gpio_num, intr_type)
/**
* @brief Get GPIO interrupt status
*
* @param hal Context of the HAL layer
* @param core_id interrupt core id
* @param status interrupt status
*/
#define gpio_hal_get_intr_status(hal, core_id, status) gpio_ll_get_intr_status((hal)->dev, core_id, status)
/**
* @brief Get GPIO interrupt status high
*
* @param hal Context of the HAL layer
* @param core_id interrupt core id
* @param status interrupt status high
*/
#define gpio_hal_get_intr_status_high(hal, core_id, status) gpio_ll_get_intr_status_high((hal)->dev, core_id, status)
/**
* @brief Clear GPIO interrupt status
*
* @param hal Context of the HAL layer
* @param mask interrupt status clear mask
*/
#define gpio_hal_clear_intr_status(hal, mask) gpio_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Clear GPIO interrupt status high
*
* @param hal Context of the HAL layer
* @param mask interrupt status high clear mask
*/
#define gpio_hal_clear_intr_status_high(hal, mask) gpio_ll_clear_intr_status_high((hal)->dev, mask)
/**
* @brief Enable GPIO module interrupt signal
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number. If you want to enable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param core_id Interrupt enabled CPU to corresponding ID
*/
void gpio_hal_intr_enable_on_core(gpio_hal_context_t *hal, gpio_num_t gpio_num, uint32_t core_id);
/**
* @brief Disable GPIO module interrupt signal
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
*/
void gpio_hal_intr_disable(gpio_hal_context_t *hal, gpio_num_t gpio_num);
/**
* @brief Disable input mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_input_disable(hal, gpio_num) gpio_ll_input_disable((hal)->dev, gpio_num)
/**
* @brief Enable input mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_input_enable(hal, gpio_num) gpio_ll_input_enable((hal)->dev, gpio_num)
/**
* @brief Disable output mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_output_disable(hal, gpio_num) gpio_ll_output_disable((hal)->dev, gpio_num)
/**
* @brief Enable output mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_output_enable(hal, gpio_num) gpio_ll_output_enable((hal)->dev, gpio_num)
/**
* @brief Disable open-drain mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_od_disable(hal, gpio_num) gpio_ll_od_disable((hal)->dev, gpio_num)
/**
* @brief Enable open-drain mode on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_od_enable(hal, gpio_num) gpio_ll_od_enable((hal)->dev, gpio_num)
/**
* @brief GPIO set output level
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param level Output level. 0: low ; 1: high
*/
#define gpio_hal_set_level(hal, gpio_num, level) gpio_ll_set_level((hal)->dev, gpio_num, level)
/**
* @brief GPIO get input level
*
* @warning If the pad is not configured for input (or input and output) the returned value is always 0.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
*
* @return
* - 0 the GPIO input level is 0
* - 1 the GPIO input level is 1
*/
#define gpio_hal_get_level(hal, gpio_num) gpio_ll_get_level((hal)->dev, gpio_num)
/**
* @brief Enable GPIO wake-up function.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
*/
#define gpio_hal_wakeup_enable(hal, gpio_num, intr_type) gpio_ll_wakeup_enable((hal)->dev, gpio_num, intr_type)
/**
* @brief Disable GPIO wake-up function.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_wakeup_disable(hal, gpio_num) gpio_ll_wakeup_disable((hal)->dev, gpio_num)
/**
* @brief Set GPIO pad drive capability
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Drive capability of the pad
*/
#define gpio_hal_set_drive_capability(hal, gpio_num, strength) gpio_ll_set_drive_capability((hal)->dev, gpio_num, strength)
/**
* @brief Get GPIO pad drive capability
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Pointer to accept drive capability of the pad
*/
#define gpio_hal_get_drive_capability(hal, gpio_num, strength) gpio_ll_get_drive_capability((hal)->dev, gpio_num, strength)
/**
* @brief Enable gpio pad hold function.
*
* The gpio pad hold function works in both input and output modes, but must be output-capable gpios.
* If pad hold enabled:
* in output mode: the output level of the pad will be force locked and can not be changed.
* in input mode: the input value read will not change, regardless the changes of input signal.
*
* The state of digital gpio cannot be held during Deep-sleep, and it will resume the hold function
* when the chip wakes up from Deep-sleep. If the digital gpio also needs to be held during Deep-sleep,
* `gpio_deep_sleep_hold_en` should also be called.
*
* Power down or call gpio_hold_dis will disable this function.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number, only support output GPIOs
*/
#define gpio_hal_hold_en(hal, gpio_num) gpio_ll_hold_en((hal)->dev, gpio_num)
/**
* @brief Disable gpio pad hold function.
*
* When the chip is woken up from Deep-sleep, the gpio will be set to the default mode, so, the gpio will output
* the default level if this function is called. If you don't want the level changes, the gpio should be configured to
* a known state before this function is called.
* e.g.
* If you hold gpio18 high during Deep-sleep, after the chip is woken up and `gpio_hold_dis` is called,
* gpio18 will output low level(because gpio18 is input mode by default). If you don't want this behavior,
* you should configure gpio18 as output mode and set it to hight level before calling `gpio_hold_dis`.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number, only support output GPIOs
*/
#define gpio_hal_hold_dis(hal, gpio_num) gpio_ll_hold_dis((hal)->dev, gpio_num)
/**
* @brief Enable all digital gpio pad hold function during Deep-sleep.
*
* When the chip is in Deep-sleep mode, all digital gpio will hold the state before sleep, and when the chip is woken up,
* the status of digital gpio will not be held. Note that the pad hold feature only works when the chip is in Deep-sleep mode,
* when not in sleep mode, the digital gpio state can be changed even you have called this function.
*
* Power down or call gpio_hold_dis will disable this function, otherwise, the digital gpio hold feature works as long as the chip enter Deep-sleep.
*
* @param hal Context of the HAL layer
*/
#define gpio_hal_deep_sleep_hold_en(hal) gpio_ll_deep_sleep_hold_en((hal)->dev)
/**
* @brief Disable all digital gpio pad hold function during Deep-sleep.
*
* @param hal Context of the HAL layer
*/
#define gpio_hal_deep_sleep_hold_dis(hal) gpio_ll_deep_sleep_hold_dis((hal)->dev)
/**
* @brief Set pad input to a peripheral signal through the IOMUX.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/
#define gpio_hal_iomux_in(hal, gpio_num, signal_idx) gpio_ll_iomux_in((hal)->dev, gpio_num, signal_idx)
/**
* @brief Set peripheral output to an GPIO pad through the IOMUX.
*
* @param hal Context of the HAL layer
* @param gpio_num gpio_num GPIO number of the pad.
* @param func The function number of the peripheral pin to output pin.
* One of the ``FUNC_X_*`` of specified pin (X) in ``soc/io_mux_reg.h``.
* @param oen_inv True if the output enable needs to be inverted, otherwise False.
*/
#define gpio_hal_iomux_out(hal, gpio_num, func, oen_inv) gpio_ll_iomux_out((hal)->dev, gpio_num, func, oen_inv)
#if SOC_GPIO_SUPPORT_FORCE_HOLD
/**
* @brief Force hold digital and rtc gpio pad.
* @note GPIO force hold, whether the chip in sleep mode or wakeup mode.
*
* @param hal Context of the HAL layer
* */
#define gpio_hal_force_hold_all(hal) gpio_ll_force_hold_all((hal)->dev)
/**
* @brief Force unhold digital and rtc gpio pad.
* @note GPIO force unhold, whether the chip in sleep mode or wakeup mode.
*
* @param hal Context of the HAL layer
* */
#define gpio_hal_force_unhold_all() gpio_ll_force_unhold_all()
#endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* @brief Enable pull-up on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pullup_en(hal, gpio_num) gpio_ll_sleep_pullup_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-up on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pullup_dis(hal, gpio_num) gpio_ll_sleep_pullup_dis((hal)->dev, gpio_num)
/**
* @brief Enable pull-down on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pulldown_en(hal, gpio_num) gpio_ll_sleep_pulldown_en((hal)->dev, gpio_num)
/**
* @brief Disable pull-down on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_pulldown_dis(hal, gpio_num) gpio_ll_sleep_pulldown_dis((hal)->dev, gpio_num)
/**
* @brief Enable sleep select on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_sel_en(hal, gpio_num) gpio_ll_sleep_sel_en((hal)->dev, gpio_num)
/**
* @brief Disable sleep select on GPIO.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_sel_dis(hal, gpio_num) gpio_ll_sleep_sel_dis((hal)->dev, gpio_num)
/**
* @brief Disable input mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_input_disable(hal, gpio_num) gpio_ll_sleep_input_disable((hal)->dev, gpio_num)
/**
* @brief Enable input mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_input_enable(hal, gpio_num) gpio_ll_sleep_input_enable((hal)->dev, gpio_num)
/**
* @brief Disable output mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_output_disable(hal, gpio_num) gpio_ll_sleep_output_disable((hal)->dev, gpio_num)
/**
* @brief Enable output mode on GPIO when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_sleep_output_enable(hal, gpio_num) gpio_ll_sleep_output_enable((hal)->dev, gpio_num)
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
/**
* @brief Apply slp_pu/slp_pd configuration to fun_pu/fun_pd when system sleep.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
*/
void gpio_hal_sleep_pupd_config_apply(gpio_hal_context_t *hal, gpio_num_t gpio_num);
/**
* @brief Restore fun_pu/fun_pd configuration when system wakeup.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
*/
void gpio_hal_sleep_pupd_config_unapply(gpio_hal_context_t *hal, gpio_num_t gpio_num);
#endif // CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
#endif //SOC_GPIO_SUPPORT_SLP_SWITCH
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
/**
* @brief Enable GPIO deep-sleep wake-up function.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number.
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
*/
#define gpio_hal_deepsleep_wakeup_enable(hal, gpio_num, intr_type) gpio_ll_deepsleep_wakeup_enable((hal)->dev, gpio_num, intr_type)
/**
* @brief Disable GPIO deep-sleep wake-up function.
*
* @param hal Context of the HAL layer
* @param gpio_num GPIO number
*/
#define gpio_hal_deepsleep_wakeup_disable(hal, gpio_num) gpio_ll_deepsleep_wakeup_disable((hal)->dev, gpio_num)
/**
* @brief Judge if the gpio is valid for waking up chip from deep-sleep
*
* @param gpio_num GPIO number
*/
#define gpio_hal_is_valid_deepsleep_wakeup_gpio(gpio_num) (gpio_num <= GPIO_NUM_5)
#endif //SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
/**
* @brief Select a function for the pin in the IOMUX
*
* @param pin_name Pin name to configure
* @param func Function to assign to the pin
*/
#define gpio_hal_iomux_func_sel(pin_name, func) gpio_ll_iomux_func_sel(pin_name, func)
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,421 @@
// 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.
#pragma once
#include "soc/gpio_periph.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
GPIO_PORT_0 = 0,
GPIO_PORT_MAX,
} gpio_port_t;
#define GPIO_SEL_0 (BIT(0)) /*!< Pin 0 selected */
#define GPIO_SEL_1 (BIT(1)) /*!< Pin 1 selected */
#define GPIO_SEL_2 (BIT(2)) /*!< Pin 2 selected */
#define GPIO_SEL_3 (BIT(3)) /*!< Pin 3 selected */
#define GPIO_SEL_4 (BIT(4)) /*!< Pin 4 selected */
#define GPIO_SEL_5 (BIT(5)) /*!< Pin 5 selected */
#define GPIO_SEL_6 (BIT(6)) /*!< Pin 6 selected */
#define GPIO_SEL_7 (BIT(7)) /*!< Pin 7 selected */
#define GPIO_SEL_8 (BIT(8)) /*!< Pin 8 selected */
#define GPIO_SEL_9 (BIT(9)) /*!< Pin 9 selected */
#define GPIO_SEL_10 (BIT(10)) /*!< Pin 10 selected */
#define GPIO_SEL_11 (BIT(11)) /*!< Pin 11 selected */
#define GPIO_SEL_12 (BIT(12)) /*!< Pin 12 selected */
#define GPIO_SEL_13 (BIT(13)) /*!< Pin 13 selected */
#define GPIO_SEL_14 (BIT(14)) /*!< Pin 14 selected */
#define GPIO_SEL_15 (BIT(15)) /*!< Pin 15 selected */
#define GPIO_SEL_16 (BIT(16)) /*!< Pin 16 selected */
#define GPIO_SEL_17 (BIT(17)) /*!< Pin 17 selected */
#define GPIO_SEL_18 (BIT(18)) /*!< Pin 18 selected */
#define GPIO_SEL_19 (BIT(19)) /*!< Pin 19 selected */
#define GPIO_SEL_20 (BIT(20)) /*!< Pin 20 selected */
#define GPIO_SEL_21 (BIT(21)) /*!< Pin 21 selected */
#if CONFIG_IDF_TARGET_ESP32
#define GPIO_SEL_22 (BIT(22)) /*!< Pin 22 selected */
#define GPIO_SEL_23 (BIT(23)) /*!< Pin 23 selected */
#define GPIO_SEL_25 (BIT(25)) /*!< Pin 25 selected */
#endif
#define GPIO_SEL_26 (BIT(26)) /*!< Pin 26 selected */
#define GPIO_SEL_27 (BIT(27)) /*!< Pin 27 selected */
#define GPIO_SEL_28 (BIT(28)) /*!< Pin 28 selected */
#define GPIO_SEL_29 (BIT(29)) /*!< Pin 29 selected */
#define GPIO_SEL_30 (BIT(30)) /*!< Pin 30 selected */
#define GPIO_SEL_31 (BIT(31)) /*!< Pin 31 selected */
#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /*!< Pin 32 selected */
#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /*!< Pin 33 selected */
#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /*!< Pin 34 selected */
#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /*!< Pin 35 selected */
#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /*!< Pin 36 selected */
#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /*!< Pin 37 selected */
#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /*!< Pin 38 selected */
#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /*!< Pin 39 selected */
#if SOC_GPIO_PIN_COUNT > 40
#define GPIO_SEL_40 ((uint64_t)(((uint64_t)1)<<40)) /*!< Pin 40 selected */
#define GPIO_SEL_41 ((uint64_t)(((uint64_t)1)<<41)) /*!< Pin 41 selected */
#define GPIO_SEL_42 ((uint64_t)(((uint64_t)1)<<42)) /*!< Pin 42 selected */
#define GPIO_SEL_43 ((uint64_t)(((uint64_t)1)<<43)) /*!< Pin 43 selected */
#define GPIO_SEL_44 ((uint64_t)(((uint64_t)1)<<44)) /*!< Pin 44 selected */
#define GPIO_SEL_45 ((uint64_t)(((uint64_t)1)<<45)) /*!< Pin 45 selected */
#define GPIO_SEL_46 ((uint64_t)(((uint64_t)1)<<46)) /*!< Pin 46 selected */
#if CONFIG_IDF_TARGET_ESP32S3
#define GPIO_SEL_47 ((uint64_t)(((uint64_t)1)<<47)) /*!< Pin 47 selected */
#define GPIO_SEL_48 ((uint64_t)(((uint64_t)1)<<48)) /*!< Pin 48 selected */
#endif
#endif
#define GPIO_PIN_REG_0 IO_MUX_GPIO0_REG
#define GPIO_PIN_REG_1 IO_MUX_GPIO1_REG
#define GPIO_PIN_REG_2 IO_MUX_GPIO2_REG
#define GPIO_PIN_REG_3 IO_MUX_GPIO3_REG
#define GPIO_PIN_REG_4 IO_MUX_GPIO4_REG
#define GPIO_PIN_REG_5 IO_MUX_GPIO5_REG
#define GPIO_PIN_REG_6 IO_MUX_GPIO6_REG
#define GPIO_PIN_REG_7 IO_MUX_GPIO7_REG
#define GPIO_PIN_REG_8 IO_MUX_GPIO8_REG
#define GPIO_PIN_REG_9 IO_MUX_GPIO9_REG
#define GPIO_PIN_REG_10 IO_MUX_GPIO10_REG
#define GPIO_PIN_REG_11 IO_MUX_GPIO11_REG
#define GPIO_PIN_REG_12 IO_MUX_GPIO12_REG
#define GPIO_PIN_REG_13 IO_MUX_GPIO13_REG
#define GPIO_PIN_REG_14 IO_MUX_GPIO14_REG
#define GPIO_PIN_REG_15 IO_MUX_GPIO15_REG
#define GPIO_PIN_REG_16 IO_MUX_GPIO16_REG
#define GPIO_PIN_REG_17 IO_MUX_GPIO17_REG
#define GPIO_PIN_REG_18 IO_MUX_GPIO18_REG
#define GPIO_PIN_REG_19 IO_MUX_GPIO19_REG
#define GPIO_PIN_REG_20 IO_MUX_GPIO20_REG
#define GPIO_PIN_REG_21 IO_MUX_GPIO21_REG
#define GPIO_PIN_REG_22 IO_MUX_GPIO22_REG
#define GPIO_PIN_REG_23 IO_MUX_GPIO23_REG
#define GPIO_PIN_REG_24 IO_MUX_GPIO24_REG
#define GPIO_PIN_REG_25 IO_MUX_GPIO25_REG
#define GPIO_PIN_REG_26 IO_MUX_GPIO26_REG
#define GPIO_PIN_REG_27 IO_MUX_GPIO27_REG
#define GPIO_PIN_REG_28 IO_MUX_GPIO28_REG
#define GPIO_PIN_REG_29 IO_MUX_GPIO29_REG
#define GPIO_PIN_REG_30 IO_MUX_GPIO30_REG
#define GPIO_PIN_REG_31 IO_MUX_GPIO31_REG
#define GPIO_PIN_REG_32 IO_MUX_GPIO32_REG
#define GPIO_PIN_REG_33 IO_MUX_GPIO33_REG
#define GPIO_PIN_REG_34 IO_MUX_GPIO34_REG
#define GPIO_PIN_REG_35 IO_MUX_GPIO35_REG
#define GPIO_PIN_REG_36 IO_MUX_GPIO36_REG
#define GPIO_PIN_REG_37 IO_MUX_GPIO37_REG
#define GPIO_PIN_REG_38 IO_MUX_GPIO38_REG
#define GPIO_PIN_REG_39 IO_MUX_GPIO39_REG
#define GPIO_PIN_REG_40 IO_MUX_GPIO40_REG
#define GPIO_PIN_REG_41 IO_MUX_GPIO41_REG
#define GPIO_PIN_REG_42 IO_MUX_GPIO42_REG
#define GPIO_PIN_REG_43 IO_MUX_GPIO43_REG
#define GPIO_PIN_REG_44 IO_MUX_GPIO44_REG
#define GPIO_PIN_REG_45 IO_MUX_GPIO45_REG
#define GPIO_PIN_REG_46 IO_MUX_GPIO46_REG
#define GPIO_PIN_REG_47 IO_MUX_GPIO47_REG
#define GPIO_PIN_REG_48 IO_MUX_GPIO48_REG
#if CONFIG_IDF_TARGET_ESP32
typedef enum {
GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_22 = 22, /*!< GPIO22, input and output */
GPIO_NUM_23 = 23, /*!< GPIO23, input and output */
GPIO_NUM_25 = 25, /*!< GPIO25, input and output */
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
GPIO_NUM_28 = 28, /*!< GPIO28, input and output */
GPIO_NUM_29 = 29, /*!< GPIO29, input and output */
GPIO_NUM_30 = 30, /*!< GPIO30, input and output */
GPIO_NUM_31 = 31, /*!< GPIO31, input and output */
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
GPIO_NUM_33 = 33, /*!< GPIO33, input and output */
GPIO_NUM_34 = 34, /*!< GPIO34, input mode only */
GPIO_NUM_35 = 35, /*!< GPIO35, input mode only */
GPIO_NUM_36 = 36, /*!< GPIO36, input mode only */
GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */
GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */
GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */
GPIO_NUM_MAX,
/** @endcond */
} gpio_num_t;
#elif CONFIG_IDF_TARGET_ESP32S2
typedef enum {
GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
GPIO_NUM_28 = 28, /*!< GPIO28, input and output */
GPIO_NUM_29 = 29, /*!< GPIO29, input and output */
GPIO_NUM_30 = 30, /*!< GPIO30, input and output */
GPIO_NUM_31 = 31, /*!< GPIO31, input and output */
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
GPIO_NUM_33 = 33, /*!< GPIO33, input and output */
GPIO_NUM_34 = 34, /*!< GPIO34, input and output */
GPIO_NUM_35 = 35, /*!< GPIO35, input and output */
GPIO_NUM_36 = 36, /*!< GPIO36, input and output */
GPIO_NUM_37 = 37, /*!< GPIO37, input and output */
GPIO_NUM_38 = 38, /*!< GPIO38, input and output */
GPIO_NUM_39 = 39, /*!< GPIO39, input and output */
GPIO_NUM_40 = 40, /*!< GPIO40, input and output */
GPIO_NUM_41 = 41, /*!< GPIO41, input and output */
GPIO_NUM_42 = 42, /*!< GPIO42, input and output */
GPIO_NUM_43 = 43, /*!< GPIO43, input and output */
GPIO_NUM_44 = 44, /*!< GPIO44, input and output */
GPIO_NUM_45 = 45, /*!< GPIO45, input and output */
GPIO_NUM_46 = 46, /*!< GPIO46, input mode only */
GPIO_NUM_MAX,
/** @endcond */
} gpio_num_t;
#elif CONFIG_IDF_TARGET_ESP32S3
typedef enum {
GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
GPIO_NUM_28 = 28, /*!< GPIO28, input and output */
GPIO_NUM_29 = 29, /*!< GPIO29, input and output */
GPIO_NUM_30 = 30, /*!< GPIO30, input and output */
GPIO_NUM_31 = 31, /*!< GPIO31, input and output */
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
GPIO_NUM_33 = 33, /*!< GPIO33, input and output */
GPIO_NUM_34 = 34, /*!< GPIO34, input and output */
GPIO_NUM_35 = 35, /*!< GPIO35, input and output */
GPIO_NUM_36 = 36, /*!< GPIO36, input and output */
GPIO_NUM_37 = 37, /*!< GPIO37, input and output */
GPIO_NUM_38 = 38, /*!< GPIO38, input and output */
GPIO_NUM_39 = 39, /*!< GPIO39, input and output */
GPIO_NUM_40 = 40, /*!< GPIO40, input and output */
GPIO_NUM_41 = 41, /*!< GPIO41, input and output */
GPIO_NUM_42 = 42, /*!< GPIO42, input and output */
GPIO_NUM_43 = 43, /*!< GPIO43, input and output */
GPIO_NUM_44 = 44, /*!< GPIO44, input and output */
GPIO_NUM_45 = 45, /*!< GPIO45, input and output */
GPIO_NUM_46 = 46, /*!< GPIO46, input and output */
GPIO_NUM_47 = 47, /*!< GPIO47, input and output */
GPIO_NUM_48 = 48, /*!< GPIO48, input and output */
GPIO_NUM_MAX,
/** @endcond */
} gpio_num_t;
#elif CONFIG_IDF_TARGET_ESP32C3
typedef enum {
GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_MAX,
/** @endcond */
} gpio_num_t;
#elif CONFIG_IDF_TARGET_ESP32H2
typedef enum {
GPIO_NUM_NC = -1, /*!< Use to signal not connected to S/W */
GPIO_NUM_0 = 0, /*!< GPIO0, input and output */
GPIO_NUM_1 = 1, /*!< GPIO1, input and output */
GPIO_NUM_2 = 2, /*!< GPIO2, input and output */
GPIO_NUM_3 = 3, /*!< GPIO3, input and output */
GPIO_NUM_4 = 4, /*!< GPIO4, input and output */
GPIO_NUM_5 = 5, /*!< GPIO5, input and output */
GPIO_NUM_6 = 6, /*!< GPIO6, input and output */
GPIO_NUM_7 = 7, /*!< GPIO7, input and output */
GPIO_NUM_8 = 8, /*!< GPIO8, input and output */
GPIO_NUM_9 = 9, /*!< GPIO9, input and output */
GPIO_NUM_10 = 10, /*!< GPIO10, input and output */
GPIO_NUM_11 = 11, /*!< GPIO11, input and output */
GPIO_NUM_12 = 12, /*!< GPIO12, input and output */
GPIO_NUM_13 = 13, /*!< GPIO13, input and output */
GPIO_NUM_14 = 14, /*!< GPIO14, input and output */
GPIO_NUM_15 = 15, /*!< GPIO15, input and output */
GPIO_NUM_16 = 16, /*!< GPIO16, input and output */
GPIO_NUM_17 = 17, /*!< GPIO17, input and output */
GPIO_NUM_18 = 18, /*!< GPIO18, input and output */
GPIO_NUM_19 = 19, /*!< GPIO19, input and output */
GPIO_NUM_20 = 20, /*!< GPIO20, input and output */
GPIO_NUM_21 = 21, /*!< GPIO21, input and output */
GPIO_NUM_22 = 22, /*!< GPIO22, input and output */
GPIO_NUM_26 = 26, /*!< GPIO26, input and output */
GPIO_NUM_27 = 27, /*!< GPIO27, input and output */
GPIO_NUM_28 = 28, /*!< GPIO28, input and output */
GPIO_NUM_29 = 29, /*!< GPIO29, input and output */
GPIO_NUM_30 = 30, /*!< GPIO30, input and output */
GPIO_NUM_31 = 31, /*!< GPIO31, input and output */
GPIO_NUM_32 = 32, /*!< GPIO32, input and output */
GPIO_NUM_33 = 33, /*!< GPIO33, input and output */
GPIO_NUM_34 = 34, /*!< GPIO34, input and output */
GPIO_NUM_35 = 35, /*!< GPIO35, input and output */
GPIO_NUM_36 = 36, /*!< GPIO36, input and output */
GPIO_NUM_37 = 37, /*!< GPIO37, input and output */
GPIO_NUM_38 = 38, /*!< GPIO38, input and output */
GPIO_NUM_39 = 39, /*!< GPIO39, input and output */
GPIO_NUM_40 = 40, /*!< GPIO40, input and output */
GPIO_NUM_MAX,
/** @endcond */
} gpio_num_t;
#endif
typedef enum {
GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */
GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */
GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */
GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */
GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */
GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */
GPIO_INTR_MAX,
} gpio_int_type_t;
/** @cond */
#define GPIO_MODE_DEF_DISABLE (0)
#define GPIO_MODE_DEF_INPUT (BIT0) ///< bit mask for input
#define GPIO_MODE_DEF_OUTPUT (BIT1) ///< bit mask for output
#define GPIO_MODE_DEF_OD (BIT2) ///< bit mask for OD mode
/** @endcond */
typedef enum {
GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE, /*!< GPIO mode : disable input and output */
GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */
GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */
GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */
GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!< GPIO mode : output and input with open-drain mode*/
GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */
} gpio_mode_t;
typedef enum {
GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */
GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */
} gpio_pullup_t;
typedef enum {
GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */
GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */
} gpio_pulldown_t;
/**
* @brief Configuration parameters of GPIO pad for gpio_config function
*/
typedef struct {
uint64_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
gpio_mode_t mode; /*!< GPIO mode: set input/output mode */
gpio_pullup_t pull_up_en; /*!< GPIO pull-up */
gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */
gpio_int_type_t intr_type; /*!< GPIO interrupt type */
} gpio_config_t;
typedef enum {
GPIO_PULLUP_ONLY, /*!< Pad pull up */
GPIO_PULLDOWN_ONLY, /*!< Pad pull down */
GPIO_PULLUP_PULLDOWN, /*!< Pad pull up + pull down*/
GPIO_FLOATING, /*!< Pad floating */
} gpio_pull_mode_t;
typedef enum {
GPIO_DRIVE_CAP_0 = 0, /*!< Pad drive capability: weak */
GPIO_DRIVE_CAP_1 = 1, /*!< Pad drive capability: stronger */
GPIO_DRIVE_CAP_2 = 2, /*!< Pad drive capability: medium */
GPIO_DRIVE_CAP_DEFAULT = 2, /*!< Pad drive capability: medium */
GPIO_DRIVE_CAP_3 = 3, /*!< Pad drive capability: strongest */
GPIO_DRIVE_CAP_MAX,
} gpio_drive_cap_t;
typedef void (*gpio_isr_t)(void *);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,567 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for I2C
#pragma once
#include "hal/i2c_ll.h"
#include "hal/i2c_types.h"
/**
* @brief I2C hal Context definition
*/
typedef struct {
i2c_dev_t *dev;
uint32_t version;
} i2c_hal_context_t;
/**
* @brief Write the I2C rxfifo with the given length
*
* @param hal Context of the HAL layer
* @param wr_data Pointer to data buffer
* @param wr_size Amount of data needs write
*
* @return None
*/
#define i2c_hal_write_txfifo(hal,wr_data,wr_size) i2c_ll_write_txfifo((hal)->dev,wr_data,wr_size)
/**
* @brief Read the I2C rxfifo with the given length
*
* @param hal Context of the HAL layer
* @param buf Pointer to data buffer
* @param rd_size Amount of data needs read
*
* @return None
*/
#define i2c_hal_read_rxfifo(hal,buf,rd_size) i2c_ll_read_rxfifo((hal)->dev,buf,rd_size)
/**
* @brief Write I2C cmd register
*
* @param hal Context of the HAL layer
* @param cmd I2C hardware command
* @param cmd_idx The index of the command register, should be less than 16
*
* @return None
*/
#define i2c_hal_write_cmd_reg(hal,cmd, cmd_idx) i2c_ll_write_cmd_reg((hal)->dev,cmd,cmd_idx)
/**
* @brief Configure the I2C to triger a transaction
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_trans_start(hal) i2c_ll_trans_start((hal)->dev)
/**
* @brief Enable I2C master RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_enable_master_rx_it(hal) i2c_ll_master_enable_rx_it((hal)->dev)
/**
* @brief Enable I2C master TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_enable_master_tx_it(hal) i2c_ll_master_enable_tx_it((hal)->dev)
/**
* @brief Clear I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_slave_clr_tx_it(hal) i2c_ll_slave_clr_tx_it((hal)->dev)
/**
* @brief Clear I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev)
/**
* @brief Set the source clock. This function is meant to be used in
* slave mode, in order to select a source clock abe to handle
* the expected SCL frequency.
*
* @param hal Context of the HAL layer
* @param src_clk Source clock to use choosen from `i2c_sclk_t` type
*/
#define i2c_hal_set_source_clk(hal, src_clk) i2c_ll_set_source_clk((hal)->dev, src_clk)
/**
* @brief Configure I2C SCL timing
*
* @param hw Beginning address of the peripheral registers
* @param high_period The I2C SCL hight period (in core clock cycle, hight_period > 2)
* @param low_period The I2C SCL low period (in core clock cycle, low_period > 1)
* @param wait_high_period The I2C SCL wait rising edge period.
*
* @return None.
*/
#define i2c_hal_set_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_set_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period)
/**
* @brief Get I2C SCL timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param high_period Pointer to accept the SCL high period
* @param low_period Pointer to accept the SCL low period
*
* @return None
*/
#define i2c_hal_get_scl_clk_timing(hal, high_period, low_period, wait_high_period) i2c_ll_get_scl_clk_timing((hal)->dev, high_period, low_period, wait_high_period)
/**
* @brief Init the I2C master.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number
*
* @return None
*/
void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num);
/**
* @brief Init the I2C slave.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number
*
* @return None
*/
void i2c_hal_slave_init(i2c_hal_context_t *hal, i2c_port_t i2c_num);
/**
* @brief Reset the I2C hw txfifo
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_txfifo_rst(i2c_hal_context_t *hal);
/**
* @brief Reset the I2C hw rxfifo
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_rxfifo_rst(i2c_hal_context_t *hal);
/**
* @brief Configure the I2C data MSB bit shifted first or LSB bit shifted first.
*
* @param hal Context of the HAL layer
* @param tx_mode Data format of TX
* @param rx_mode Data format of RX
*
* @return None
*/
void i2c_hal_set_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode);
/**
* @brief Configure the I2C hardware filter function.
*
* @param hal Context of the HAL layer
* @param filter_num If the glitch period on the line is less than this value(in APB cycle), it will be filtered out
* If `filter_num == 0`, the filter will be disabled
*
* @return None
*/
void i2c_hal_set_filter(i2c_hal_context_t *hal, uint8_t filter_num);
/**
* @brief Get the I2C hardware filter configuration
*
* @param hal Context of the HAL layer
* @param filter_num Pointer to accept the hardware filter configuration
*
* @return None
*/
void i2c_hal_get_filter(i2c_hal_context_t *hal, uint8_t *filter_num);
/**
* @brief Configure the I2C SCL timing
*
* @param hal Context of the HAL layer
* @param hight_period SCL high period
* @param low_period SCL low period
*
* @return None
*/
void i2c_hal_set_scl_timing(i2c_hal_context_t *hal, int hight_period, int low_period);
/**
* @brief Configure the I2C master SCL frequency
*
* @param hal Context of the HAL layer
* @param src_clk The I2C Source clock frequency
* @param scl_freq The SCL frequency to be set
*
* @return None
*/
void i2c_hal_set_scl_freq(i2c_hal_context_t *hal, uint32_t src_clk, uint32_t scl_freq);
/**
* @brief Clear the I2C interrupt status with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be clearned
*
* @return None
*/
void i2c_hal_clr_intsts_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Enable the I2C interrupt with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be enabled
*
* @return None
*/
void i2c_hal_enable_intr_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Disable the I2C interrupt with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be disabled
*
* @return None
*/
void i2c_hal_disable_intr_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Configure the I2C memory access mode, FIFO mode or none FIFO mode
*
* @param hal Context of the HAL layer
* @param fifo_mode_en Set true to enable FIFO access mode, else set it false
*
* @return None
*/
void i2c_hal_set_fifo_mode(i2c_hal_context_t *hal, bool fifo_mode_en);
/**
* @brief Configure the I2C timeout value
*
* @param hal Context of the HAL layer
* @param tout_val the timeout value to be set
*
* @return None
*/
void i2c_hal_set_tout(i2c_hal_context_t *hal, int tout_val);
/**
* @brief Get the I2C time out configuration
*
* @param tout_val Pointer to accept the timeout configuration
*
* @return None
*/
void i2c_hal_get_tout(i2c_hal_context_t *hal, int *tout_val);
/**
* @brief Configure the I2C slave address
*
* @param hal Context of the HAL layer
* @param slave_addr Slave address
* @param addr_10bit_en Set true to enable 10-bit slave address mode, Set false to enable 7-bit address mode
*
* @return None
*/
void i2c_hal_set_slave_addr(i2c_hal_context_t *hal, uint16_t slave_addr, bool addr_10bit_en);
/**
* @brief Configure the I2C stop timing
*
* @param hal Context of the HAL layer
* @param stop_setup The stop condition setup period (in APB cycle)
* @param stop_hold The stop condition hold period (in APB cycle)
*
* @return None
*/
void i2c_hal_set_stop_timing(i2c_hal_context_t *hal, int stop_setup, int stop_hold);
/**
* @brief Configure the I2C start timing
*
* @param hal Context of the HAL layer
* @param start_setup The start condition setup period (in APB cycle)
* @param start_hold The start condition hold period (in APB cycle)
*
* @return None
*/
void i2c_hal_set_start_timing(i2c_hal_context_t *hal, int start_setup, int start_hold);
/**
* @brief Configure the I2C sda sample timing
*
* @param hal Context of the HAL layer
* @param sda_sample The SDA sample time (in APB cycle)
* @param sda_hold The SDA hold time (in APB cycle)
*
* @return None
*/
void i2c_hal_set_sda_timing(i2c_hal_context_t *hal, int sda_sample, int sda_hold);
/**
* @brief Configure the I2C txfifo empty threshold value
*
* @param hal Context of the HAL layer.
* @param empty_thr TxFIFO empty threshold value
*
* @return None
*/
void i2c_hal_set_txfifo_empty_thr(i2c_hal_context_t *hal, uint8_t empty_thr);
/**
* @brief Configure the I2C rxfifo full threshold value
*
* @param hal Context of the HAL layer
* @param full_thr RxFIFO full threshold value
*
* @return None
*/
void i2c_hal_set_rxfifo_full_thr(i2c_hal_context_t *hal, uint8_t full_thr);
/**
* @brief Get the I2C interrupt status
*
* @param hal Context of the HAL layer
* @param mask Pointer to accept the interrupt status
*
* @return None
*/
void i2c_hal_get_intsts_mask(i2c_hal_context_t *hal, uint32_t *mask);
/**
* @brief Check if the I2C bus is busy
*
* @param hal Context of the HAL layer
*
* @return True if the bus is busy, otherwise, fale will be returned
*/
bool i2c_hal_is_bus_busy(i2c_hal_context_t *hal);
/**
* @brief Get the I2C sda sample timing configuration
*
* @param hal Context of the HAL layer
* @param sample_time Pointer to accept the SDA sample time
* @param hold_time Pointer to accept the SDA hold time
*
* @return None
*/
void i2c_hal_get_sda_timing(i2c_hal_context_t *hal, int *sample_time, int *hold_time);
/**
* @brief Get the I2C stop timing configuration
*
* @param hal Context of the HAL layer
* @param setup_time Pointer to accept the stop condition setup period
* @param hold_time Pointer to accept the stop condition hold period
*
* @return None
*/
void i2c_hal_get_stop_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time);
/**
* @brief Get the I2C scl timing configuration
*
* @param hal Context of the HAL layer
* @param high_period Pointer to accept the scl high period
* @param low_period Pointer to accept the scl low period
*
* @return None
*/
void i2c_hal_get_scl_timing(i2c_hal_context_t *hal, int *high_period, int *low_period);
/**
* @brief Get the I2C start timing configuration
*
* @param hal Context of the HAL layer
* @param setup_time Pointer to accept the start condition setup period
* @param hold_time Pointer to accept the start condition hold period
*
* @return None
*/
void i2c_hal_get_start_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time);
/**
* @brief Check if the I2C is master mode
*
* @param hal Context of the HAL layer
*
* @return True if in master mode, otherwise, false will be returned
*/
bool i2c_hal_is_master_mode(i2c_hal_context_t *hal);
/**
* @brief Get the rxFIFO readable length
*
* @param hal Context of the HAL layer
* @param len Pointer to accept the rxFIFO readable length
*
* @return None
*/
void i2c_hal_get_rxfifo_cnt(i2c_hal_context_t *hal, uint32_t *len);
/**
* @brief Set I2C bus timing with the given frequency
*
* @param hal Context of the HAL layer
* @param scl_freq The scl frequency to be set
* @param src_clk Source clock of I2C
*
* @return None
*/
void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, int scl_freq, i2c_sclk_t src_clk);
/**
* @brief Get I2C txFIFO writeable length
*
* @param hal Context of the HAL layer
* @param len Pointer to accept the txFIFO writeable length
*
* @return None
*/
void i2c_hal_get_txfifo_cnt(i2c_hal_context_t *hal, uint32_t *len);
/**
* @brief Check if the I2C is master mode
*
* @param hal Context of the HAL layer
* @param tx_mode Pointer to accept the TX data mode
* @param rx_mode Pointer to accept the RX data mode
*
* @return None
*/
void i2c_hal_get_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode);
/**
* @brief I2C hardware FSM reset
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal);
/**
* @brief @brief Clear I2C bus
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_master_clr_bus(i2c_hal_context_t *hal);
/**
* @brief Enable I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_enable_slave_tx_it(i2c_hal_context_t *hal);
/**
* @brief Disable I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_disable_slave_tx_it(i2c_hal_context_t *hal);
/**
* @brief Enable I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_enable_slave_rx_it(i2c_hal_context_t *hal);
/**
* @brief Disable I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal);
/**
* @brief I2C master handle tx interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief I2C master handle rx interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief I2C slave handle interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief Synchronize I2C status
*
* @param hal Context of the HAL layer
*
* @return None
*
*/
void i2c_hal_update_config(i2c_hal_context_t *hal);

View File

@@ -0,0 +1,97 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
/**
* @brief I2C port number, can be I2C_NUM_0 ~ (I2C_NUM_MAX-1).
*/
typedef int i2c_port_t;
typedef enum{
I2C_MODE_SLAVE = 0, /*!< I2C slave mode */
I2C_MODE_MASTER, /*!< I2C master mode */
I2C_MODE_MAX,
} i2c_mode_t;
typedef enum {
I2C_MASTER_WRITE = 0, /*!< I2C write data */
I2C_MASTER_READ, /*!< I2C read data */
} i2c_rw_t;
typedef enum {
I2C_DATA_MODE_MSB_FIRST = 0, /*!< I2C data msb first */
I2C_DATA_MODE_LSB_FIRST = 1, /*!< I2C data lsb first */
I2C_DATA_MODE_MAX
} i2c_trans_mode_t;
typedef enum {
I2C_ADDR_BIT_7 = 0, /*!< I2C 7bit address for slave mode */
I2C_ADDR_BIT_10, /*!< I2C 10bit address for slave mode */
I2C_ADDR_BIT_MAX,
} i2c_addr_mode_t;
typedef enum {
I2C_MASTER_ACK = 0x0, /*!< I2C ack for each byte read */
I2C_MASTER_NACK = 0x1, /*!< I2C nack for each byte read */
I2C_MASTER_LAST_NACK = 0x2, /*!< I2C nack for the last byte*/
I2C_MASTER_ACK_MAX,
} i2c_ack_type_t;
/**
* @brief I2C clock source, sorting from smallest to largest,
* place them in order.
* This can be expanded in the future use.
*/
typedef enum {
I2C_SCLK_DEFAULT = 0, /*!< I2C source clock not selected*/
#if SOC_I2C_SUPPORT_APB
I2C_SCLK_APB, /*!< I2C source clock from APB, 80M*/
#endif
#if SOC_I2C_SUPPORT_XTAL
I2C_SCLK_XTAL, /*!< I2C source clock from XTAL, 40M */
#endif
#if SOC_I2C_SUPPORT_RTC
I2C_SCLK_RTC, /*!< I2C source clock from 8M RTC, 8M */
#endif
#if SOC_I2C_SUPPORT_REF_TICK
I2C_SCLK_REF_TICK, /*!< I2C source clock from REF_TICK, 1M */
#endif
I2C_SCLK_MAX,
} i2c_sclk_t;
/// Use the highest speed that is available for the clock source picked by clk_flags
#define I2C_CLK_FREQ_MAX (-1)
#if CONFIG_IDF_TARGET_ESP32
typedef enum{
I2C_CMD_RESTART = 0, /*!<I2C restart command */
I2C_CMD_WRITE, /*!<I2C write command */
I2C_CMD_READ, /*!<I2C read command */
I2C_CMD_STOP, /*!<I2C stop command */
I2C_CMD_END /*!<I2C end command */
} i2c_opmode_t __attribute__((deprecated));
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,555 @@
/*
* SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
*
* 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
******************************************************************************/
// The HAL layer for I2S.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/i2s_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_types.h"
#include "hal/i2s_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S clock configuration
*/
typedef struct {
uint32_t sclk; /*!< I2S module clock */
uint32_t mclk; /*!< I2S master clock */
uint32_t bclk; /*!< I2S bit clock */
uint16_t mclk_div; /*!< I2S master clock division */
uint16_t bclk_div; /*!< I2S bit clock division*/
} i2s_hal_clock_cfg_t;
/**
* @brief I2S HAL configurations
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode, using ored mask of `i2s_mode_t`*/
uint32_t sample_rate; /*!< I2S sample rate*/
i2s_comm_format_t comm_fmt; /*!< I2S communication format */
i2s_channel_fmt_t chan_fmt; /*!< I2S channel format, there are total 16 channels in TDM mode.*/
uint32_t sample_bits; /*!< I2S sample bits in one channel */
uint32_t chan_bits; /*!< I2S total bits in one channel. Should not be smaller than 'sample_bits', default '0' means equal to 'sample_bits' */
uint32_t active_chan; /*!< I2S active channel number */
uint32_t total_chan; /*!< Total number of I2S channels */
#if SOC_I2S_SUPPORTS_TDM
uint32_t chan_mask; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<<total_chan_num). */
bool left_align; /*!< Set to enable left aligment */
bool big_edin; /*!< Set to enable big edin */
bool bit_order_msb; /*!< Set to enable msb order */
bool skip_msk; /*!< Set to enable skip mask. If it is enabled, only the data of the enabled channels will be sent, otherwise all data stored in DMA TX buffer will be sent */
#endif
} i2s_hal_config_t;
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
i2s_dev_t *dev;
uint32_t version;
} i2s_hal_context_t;
/**
* @brief Enable I2S module clock
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_module_clock(hal) i2s_ll_enable_clock((hal)->dev);
/**
* @brief Disable I2S module clock
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_module_clock(hal) i2s_ll_disable_clock((hal)->dev);
/**
* @brief Reset I2S TX channel
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_tx(hal) i2s_ll_tx_reset((hal)->dev)
/**
* @brief Reset I2S TX fifo
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_tx_fifo(hal) i2s_ll_tx_reset_fifo((hal)->dev)
/**
* @brief Reset I2S RX channel
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_rx(hal) i2s_ll_rx_reset((hal)->dev)
/**
* @brief Reset I2S RX fifo
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_rx_fifo(hal) i2s_ll_rx_reset_fifo((hal)->dev)
/**
* @brief Get I2S hardware instance and enable I2S module clock
* @note This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1)
*/
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
/**
* @brief Configure I2S source clock
*
* @param hal Context of the HAL layer
* @param sel The source clock index
*/
void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel);
/**
* @brief Calculate the closest sample rate clock configuration.
* clock relationship:
* Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a)
*
* @param clk_cfg I2S clock configuration(input)
* @param cal Point to `i2s_ll_mclk_div_t` structure(output).
*/
void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mclk_div_t *cal);
/**
* @brief Set Tx channel style
*
* @param hal Context of the HAL layer
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
*/
void i2s_hal_tx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Set Rx channel style
*
* @param hal Context of the HAL layer
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
*/
void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Initialize I2S hardware
*
* @param hal Context of the HAL layer
* @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t`
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Enable I2S master full-duplex mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_master_fd_mode(i2s_hal_context_t *hal);
/**
* @brief Enable I2S slave full-duplex mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal);
/**
* @brief Start I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_tx(i2s_hal_context_t *hal);
/**
* @brief Start I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_rx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_tx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_rx(i2s_hal_context_t *hal);
/**
* @brief Set the received data length to trigger `in_suc_eof` interrupt.
*
* @param hal Context of the HAL layer
* @param eof_byte The byte length that trigger in_suc_eof interrupt.
*/
#define i2s_hal_set_rx_eof_num(hal, eof_byte) i2s_ll_rx_set_eof_num((hal)->dev, eof_byte)
/**
* @brief Set I2S TX sample bit
*
* @param hal Context of the HAL layer
* @param chan_bit I2S TX chan bit
* @param data_bit The sample data bit length.
*/
#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_tx_set_sample_bit((hal)->dev, chan_bit, data_bit)
/**
* @brief Set I2S RX sample bit
*
* @param hal Context of the HAL layer
* @param chan_bit I2S RX chan bit
* @param data_bit The sample data bit length.
*/
#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_rx_set_sample_bit((hal)->dev, chan_bit, data_bit)
/**
* @brief Configure I2S TX module clock devider
*
* @param hal Context of the HAL layer
* @param clk_cfg I2S clock configuration
*/
void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg);
/**
* @brief Configure I2S RX module clock devider
*
* @param hal Context of the HAL layer
* @param clk_cfg I2S clock configuration
*/
void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg);
/**
* @brief Set I2S tx clock source
*
* @param hal Context of the HAL layer
* @param clk_src i2s tx clock source (see 'i2s_clock_src_t')
*/
#define i2s_hal_tx_set_clock_source(hal, clk_src) i2s_ll_tx_clk_set_src((hal)->dev, clk_src)
/**
* @brief Set I2S rx clock source
*
* @param hal Context of the HAL layer
* @param clk_src i2s rx clock source (see 'i2s_clock_src_t')
*/
#define i2s_hal_rx_set_clock_source(hal, clk_src) i2s_ll_rx_clk_set_src((hal)->dev, clk_src)
/**
* @brief Enable I2S tx slave mode
*
* @param hal Context of the HAL layer
* @param enable set 'true' to enable tx slave mode
*/
#define i2s_hal_tx_enable_slave_mode(hal, enable) i2s_ll_tx_set_slave_mod((hal)->dev, enable)
/**
* @brief Enable I2S rx slave mode
*
* @param hal Context of the HAL layer
* @param enable set 'true' to enable rx slave mode
*/
#define i2s_hal_rx_enable_slave_mode(hal, enable) i2s_ll_rx_set_slave_mod((hal)->dev, enable)
/**
* @brief Enable loopback mode
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_share_bck_ws((hal)->dev, true)
/**
* @brief Set I2S configuration for common TX mode
* @note Common mode is for non-PDM mode like philip/MSB/PCM
*
* @param hal Context of the HAL layer
* @param hal_cfg hal configuration structure
*/
void i2s_hal_tx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
/**
* @brief Set I2S configuration for common RX mode
* @note Common mode is for non-PDM mode like philip/MSB/PCM
*
* @param hal Context of the HAL layer
* @param hal_cfg hal configuration structure
*/
void i2s_hal_rx_set_common_mode(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg);
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief Configure I2S TX PCM encoder or decoder.
*
* @param hal Context of the HAL layer
* @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
*/
#define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_set_pcm_type((hal)->dev, cfg)
/**
* @brief Configure I2S RX PCM encoder or decoder.
*
* @param hal Context of the HAL layer
* @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t`
*/
#define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_set_pcm_type((hal)->dev, cfg)
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
/**
* @brief Configure I2S TX PDM sample rate
* Fpdm = 64*Fpcm*fp/fs
*
* @param hal Context of the HAL layer
* @param fp TX PDM fp paramater configuration
* @param fs TX PDM fs paramater configuration
*/
#define i2s_hal_set_tx_pdm_fpfs(hal, fp, fs) i2s_ll_tx_set_pdm_fpfs((hal)->dev, fp, fs)
/**
* @brief Get I2S TX PDM fp
*
* @param hal Context of the HAL layer
* @return
* - fp configuration paramater
*/
#define i2s_hal_get_tx_pdm_fp(hal) i2s_ll_tx_get_pdm_fp((hal)->dev)
/**
* @brief Get I2S TX PDM fs
*
* @param hal Context of the HAL layer
* @return
* - fs configuration paramater
*/
#define i2s_hal_get_tx_pdm_fs(hal) i2s_ll_tx_get_pdm_fs((hal)->dev)
/**
* @brief Set I2S default configuration for PDM TX mode
*
* @param hal Context of the HAL layer
* @param sample_rate PDM sample rate
* @param is_mono whether is mono
*/
void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate, bool is_mono);
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief Configure RX PDM downsample
*
* @param hal Context of the HAL layer
* @param dsr PDM downsample configuration paramater
*/
#define i2s_hal_set_rx_pdm_dsr(hal, dsr) i2s_ll_rx_set_pdm_dsr((hal)->dev, dsr)
/**
* @brief Get RX PDM downsample configuration
*
* @param hal Context of the HAL layer
* @param dsr Pointer to accept PDM downsample configuration
*/
#define i2s_hal_get_rx_pdm_dsr(hal, dsr) i2s_ll_rx_get_pdm_dsr((hal)->dev, dsr)
/**
* @brief Set I2S default configuration for PDM R mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal);
#endif
#if !SOC_GDMA_SUPPORTED
/**
* @brief Enable I2S TX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,true)
/**
* @brief Enable I2S RX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,true)
/**
* @brief Disable I2S TX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_tx_dma(hal) i2s_ll_enable_dma((hal)->dev,false)
/**
* @brief Disable I2S RX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_rx_dma(hal) i2s_ll_enable_dma((hal)->dev,false)
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @return
* - module interrupt status
*/
#define i2s_hal_get_intr_status(hal) i2s_ll_get_intr_status((hal)->dev)
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param mask Interrupt mask to be cleared.
*/
#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Enable I2S RX interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_intr(hal) i2s_ll_rx_enable_intr((hal)->dev)
/**
* @brief Disable I2S RX interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_rx_intr(hal) i2s_ll_rx_disable_intr((hal)->dev)
/**
* @brief Disable I2S TX interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_tx_intr(hal) i2s_ll_tx_disable_intr((hal)->dev)
/**
* @brief Enable I2S TX interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_tx_intr(hal) i2s_ll_tx_enable_intr((hal)->dev)
/**
* @brief Configure TX DMA descriptor address and start TX DMA
*
* @param hal Context of the HAL layer
* @param link_addr DMA descriptor link address.
*/
#define i2s_hal_start_tx_link(hal, link_addr) i2s_ll_tx_start_link((hal)->dev, link_addr)
/**
* @brief Configure RX DMA descriptor address and start RX DMA
*
* @param hal Context of the HAL layer
* @param link_addr DMA descriptor link address.
*/
#define i2s_hal_start_rx_link(hal, link_addr) i2s_ll_rx_start_link((hal)->dev, link_addr)
/**
* @brief Stop TX DMA link
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_stop_tx_link(hal) i2s_ll_tx_stop_link((hal)->dev)
/**
* @brief Stop RX DMA link
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_stop_rx_link(hal) i2s_ll_rx_stop_link((hal)->dev)
/**
* @brief Reset RX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_rxdma(hal) i2s_ll_rx_reset_dma((hal)->dev)
/**
* @brief Reset TX DMA
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_reset_txdma(hal) i2s_ll_tx_reset_dma((hal)->dev)
/**
* @brief Get I2S out eof descriptor address
*
* @param hal Context of the HAL layer
* @param addr Pointer to accept out eof des address
*/
#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_tx_get_eof_des_addr((hal)->dev, addr)
/**
* @brief Get I2S in suc eof descriptor address
*
* @param hal Context of the HAL layer
* @param addr Pointer to accept in suc eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_rx_get_eof_des_addr((hal)->dev, addr)
#endif
#if SOC_I2S_SUPPORTS_ADC
/**
* @brief Enable Builtin DAC
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, true);
/**
* @brief Enable Builtin ADC
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, true);
/**
* @brief Disable Builtin ADC
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, false);
#endif
#if SOC_I2S_SUPPORTS_DAC
/**
* @brief Disable Builtin DAC
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, false);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,200 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stddef.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< data bit-width: 8 */
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< data bit-width: 16 */
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< data bit-width: 24 */
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< data bit-width: 32 */
} i2s_bits_per_sample_t;
/**
* @brief I2S bit width per chan.
*
*/
typedef enum {
I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< channel bit-width equals to data bit-width */
I2S_BITS_PER_CHAN_8BIT = (8), /*!< channel bit-width: 8 */
I2S_BITS_PER_CHAN_16BIT = (16), /*!< channel bit-width: 16 */
I2S_BITS_PER_CHAN_24BIT = (24), /*!< channel bit-width: 24 */
I2S_BITS_PER_CHAN_32BIT = (32), /*!< channel bit-width: 32 */
} i2s_bits_per_chan_t;
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S channel (mono), one channel activated. In this mode, you only need to send one channel data but the fifo will copy same data for the other unactivated channels automatically, then both channels will transmit same data. */
I2S_CHANNEL_STEREO = 2, /*!< I2S channel (stereo), two (or more) channels activated. In this mode, these channels will transmit different data. */
#if SOC_I2S_SUPPORTS_TDM
// Bit map of activated chan.
// There are 16 channels in TDM mode.
// For TX module, only the activated channel send the audio data, the unactivated channel send a constant(configurable) or will be skiped if 'skip_msk' is set.
// For RX module, only receive the audio data in activated channels, the data in unactivated channels will be ignored.
// the bit map of activated channel can not exceed the maximum enabled channel number (i.e. 0x10000 << total_chan_num).
// e.g: active_chan_mask = (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH3), here the active_chan_number is 2 and total_chan_num is not supposed to be smaller than 4.
I2S_TDM_ACTIVE_CH0 = (0x1 << 16), /*!< I2S channel 0 activated */
I2S_TDM_ACTIVE_CH1 = (0x1 << 17), /*!< I2S channel 1 activated */
I2S_TDM_ACTIVE_CH2 = (0x1 << 18), /*!< I2S channel 2 activated */
I2S_TDM_ACTIVE_CH3 = (0x1 << 19), /*!< I2S channel 3 activated */
I2S_TDM_ACTIVE_CH4 = (0x1 << 20), /*!< I2S channel 4 activated */
I2S_TDM_ACTIVE_CH5 = (0x1 << 21), /*!< I2S channel 5 activated */
I2S_TDM_ACTIVE_CH6 = (0x1 << 22), /*!< I2S channel 6 activated */
I2S_TDM_ACTIVE_CH7 = (0x1 << 23), /*!< I2S channel 7 activated */
I2S_TDM_ACTIVE_CH8 = (0x1 << 24), /*!< I2S channel 8 activated */
I2S_TDM_ACTIVE_CH9 = (0x1 << 25), /*!< I2S channel 9 activated */
I2S_TDM_ACTIVE_CH10 = (0x1 << 26), /*!< I2S channel 10 activated */
I2S_TDM_ACTIVE_CH11 = (0x1 << 27), /*!< I2S channel 11 activated */
I2S_TDM_ACTIVE_CH12 = (0x1 << 28), /*!< I2S channel 12 activated */
I2S_TDM_ACTIVE_CH13 = (0x1 << 29), /*!< I2S channel 13 activated */
I2S_TDM_ACTIVE_CH14 = (0x1 << 30), /*!< I2S channel 14 activated */
I2S_TDM_ACTIVE_CH15 = (0x1 << 31), /*!< I2S channel 15 activated */
#endif
} i2s_channel_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X02, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/
I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/
I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/
//old definition will be removed in the future.
I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/
I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT, /*!< Separated left and right channel */
I2S_CHANNEL_FMT_ALL_RIGHT, /*!< Load right channel data in both two channels */
I2S_CHANNEL_FMT_ALL_LEFT, /*!< Load left channel data in both two channels */
I2S_CHANNEL_FMT_ONLY_RIGHT, /*!< Only load data in right channel (mono mode) */
I2S_CHANNEL_FMT_ONLY_LEFT, /*!< Only load data in left channel (mono mode) */
#if SOC_I2S_SUPPORTS_TDM
// Multiple channels are available with TDM feature
I2S_CHANNEL_FMT_MULTIPLE, /*!< More than two channels are used */
#endif
} i2s_channel_fmt_t;
/**
* @brief I2S Mode
*/
typedef enum {
I2S_MODE_MASTER = (0x1 << 0), /*!< Master mode*/
I2S_MODE_SLAVE = (0x1 << 1), /*!< Slave mode*/
I2S_MODE_TX = (0x1 << 2), /*!< TX mode*/
I2S_MODE_RX = (0x1 << 3), /*!< RX mode*/
#if SOC_I2S_SUPPORTS_DAC
//built-in DAC functions are only supported on I2S0 for ESP32 chip.
I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
#endif // SOC_I2S_SUPPORTS_DAC
#if SOC_I2S_SUPPORTS_ADC
I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif // SOC_I2S_SUPPORTS_ADC
// PDM functions are only supported on I2S0 (all chips).
I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/
} i2s_mode_t;
/**
* @brief I2S source clock
*/
typedef enum {
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
#if SOC_I2S_SUPPORTS_APLL
I2S_CLK_APLL, /*!< Clock from APLL*/
#endif
} i2s_clock_src_t;
/**
* @brief The multiple of mclk to sample rate
*/
typedef enum {
I2S_MCLK_MULTIPLE_DEFAULT = 0, /*!< Default value. mclk = sample_rate * 256 */
I2S_MCLK_MULTIPLE_128 = 128, /*!< mclk = sample_rate * 128 */
I2S_MCLK_MULTIPLE_256 = 256, /*!< mclk = sample_rate * 256 */
I2S_MCLK_MULTIPLE_384 = 384, /*!< mclk = sample_rate * 384 */
} i2s_mclk_multiple_t;
#if SOC_I2S_SUPPORTS_DAC
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
*
* @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*/
typedef enum {
I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/
I2S_DAC_CHANNEL_RIGHT_EN = 1, /*!< Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25*/
I2S_DAC_CHANNEL_LEFT_EN = 2, /*!< Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26*/
I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/
I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/
} i2s_dac_mode_t;
#endif //SOC_I2S_SUPPORTS_DAC
#if SOC_I2S_SUPPORTS_PCM
/**
* @brief A/U-law decompress or compress configuration.
*
*/
typedef enum {
I2S_PCM_DISABLE = 0, /*!< Disable A/U law decopress or compress*/
I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/
I2S_PCM_A_COMPRESS, /*!< A-law compress*/
I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/
I2S_PCM_U_COMPRESS, /*!< U-law compress*/
} i2s_pcm_compress_t;
#endif
#if SOC_I2S_SUPPORTS_PDM_RX
/**
* @brief I2S PDM RX downsample mode
*/
typedef enum {
I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
#endif
#if SOC_I2S_SUPPORTS_PDM_TX
typedef enum {
I2S_PDM_SIG_SCALING_DIV_2 = 0, /*!< I2S TX PDM sigmadelta signal scaling: /2 */
I2S_PDM_SIG_SCALING_MUL_1 = 1, /*!< I2S TX PDM sigmadelta signal scaling: x1 */
I2S_PDM_SIG_SCALING_MUL_2 = 2, /*!< I2S TX PDM sigmadelta signal scaling: x2 */
I2S_PDM_SIG_SCALING_MUL_4 = 3, /*!< I2S TX PDM sigmadelta signal scaling: x4 */
} i2s_pdm_sig_scale_t;
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,196 @@
// 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.
#pragma once
#include <stdbool.h>
#include "hal/interrupt_controller_types.h"
#include "hal/interrupt_controller_ll.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
/**
* @brief Gets target platform interrupt descriptor table
*
* @return Address of interrupt descriptor table
*/
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
#endif
/**
* @brief Gets the interrupt type given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt type
*/
__attribute__((pure)) int_type_t interrupt_controller_hal_desc_type(int interrupt_number);
/**
* @brief Gets the interrupt level given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt level bitmask
*/
__attribute__((pure)) int interrupt_controller_hal_desc_level(int interrupt_number);
/**
* @brief Gets the cpu flags given the interrupt number and target cpu.
*
* @param interrupt_number Interrupt number 0 to 31
* @param cpu_number CPU number between 0 and SOC_CPU_CORES_NUM - 1
* @return flags for that interrupt number
*/
__attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number);
/**
* @brief Gets the interrupt type given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt type
*/
static inline int_type_t interrupt_controller_hal_get_type(int interrupt_number)
{
return interrupt_controller_hal_desc_type(interrupt_number);
}
/**
* @brief Gets the interrupt level given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt level bitmask
*/
static inline int interrupt_controller_hal_get_level(int interrupt_number)
{
return interrupt_controller_hal_desc_level(interrupt_number);
}
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/**
* @brief Set the type of an interrupt in the controller.
*
* @param interrupt_number Interrupt number 0 to 31
* @param type interrupt type as edge or level triggered
*/
static inline void interrupt_controller_hal_set_int_type(int intr, int_type_t type)
{
intr_cntrl_ll_set_int_type(intr, type);
}
/**
* @brief Sets the interrupt level int the interrupt controller.
*
* @param interrupt_number Interrupt number 0 to 31
* @param level priority between 1 (lowest) to 7 (highest)
*/
static inline void interrupt_controller_hal_set_int_level(int intr, int level)
{
intr_cntrl_ll_set_int_level(intr, level);
}
#endif
/**
* @brief Gets the cpu flags given the interrupt number and target cpu.
*
* @param interrupt_number Interrupt number 0 to 31
* @param cpu_number CPU number between 0 and SOC_CPU_CORES_NUM - 1
* @return flags for that interrupt number
*/
static inline uint32_t interrupt_controller_hal_get_cpu_desc_flags(int interrupt_number, int cpu_number)
{
return interrupt_controller_hal_desc_flags(interrupt_number, cpu_number);
}
/**
* @brief enable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be enabled
*/
static inline void interrupt_controller_hal_enable_interrupts(uint32_t mask)
{
intr_cntrl_ll_enable_interrupts(mask);
}
/**
* @brief disable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be disabled
*/
static inline void interrupt_controller_hal_disable_interrupts(uint32_t mask)
{
intr_cntrl_ll_disable_interrupts(mask);
}
/**
* @brief Read the current interrupt mask.
*
* @return The bitmask of current interrupts
*/
static inline uint32_t interrupt_controller_hal_read_interrupt_mask(void)
{
return intr_cntrl_ll_read_interrupt_mask();
}
/**
* @brief checks if given interrupt number has a valid handler
*
* @param intr interrupt number ranged from 0 to 31
* @param cpu cpu number ranged betweeen 0 to SOC_CPU_CORES_NUM - 1
* @return true for valid handler, false otherwise
*/
static inline bool interrupt_controller_hal_has_handler(int intr, int cpu)
{
return intr_cntrl_ll_has_handler(intr, cpu);
}
/**
* @brief sets interrupt handler and optional argument of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
* @param handler handler invoked when an interrupt occurs
* @param arg optional argument to pass to the handler
*/
static inline void interrupt_controller_hal_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
{
intr_cntrl_ll_set_int_handler(intr, handler, arg);
}
/**
* @brief Gets argument passed to handler of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
*
* @return argument used by handler of passed interrupt number
*/
static inline void * interrupt_controller_hal_get_int_handler_arg(uint8_t intr)
{
return intr_cntrl_ll_get_int_handler_arg(intr);
}
/**
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
*
* @param intr interrupt number ranged from 0 to 31
*/
static inline void interrupt_controller_hal_edge_int_acknowledge(int intr)
{
intr_cntrl_ll_edge_int_acknowledge(intr);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,46 @@
// 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.
#pragma once
#include "soc/soc_caps.h"
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
INTDESC_NORMAL=0,
INTDESC_RESVD,
INTDESC_SPECIAL,
} int_desc_flag_t;
typedef enum {
INTTP_LEVEL=0,
INTTP_EDGE,
INTTP_NA,
} int_type_t;
typedef struct {
int level;
int_type_t type;
int_desc_flag_t cpuflags[SOC_CPU_CORES_NUM];
} int_desc_t;
typedef void (*interrupt_handler_t)(void *arg);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LCD peripheral SOC layer handle
*/
typedef struct lcd_cam_dev_t *lcd_soc_handle_t;
/**
* @brief LCD HAL layer context
*/
typedef struct {
lcd_soc_handle_t dev; // SOC layer handle
} lcd_hal_context_t;
/**
* @brief LCD HAL layer initialization
*
* @param hal LCD HAL layer context
* @param id LCD peripheral ID
*/
void lcd_hal_init(lcd_hal_context_t *hal, int id);
#define LCD_HAL_PCLK_FLAG_ALLOW_EQUAL_SYSCLK (1 << 0)
/**
* @brief LCD PCLK clock calculation
* @note Currently this function is only used by RGB LCD driver, I80 driver still uses a fixed clock division
*
* @param hal LCD HAL layer context
* @param src_freq_hz LCD source clock frequency in Hz
* @param expect_pclk_freq_hz Expected LCD PCLK frequency in Hz
* @param lcd_clk_flags Extra flags to control LCD PCLK clock calculation, supported flags are prefixed with LCD_HAL_PCLK_FLAG_
* @return Actual LCD PCLK frequency in Hz
*/
uint32_t lcd_hal_cal_pclk_freq(lcd_hal_context_t *hal, uint32_t src_freq_hz, uint32_t expect_pclk_freq_hz, int lcd_clk_flags);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LCD clock source
* @note User should select the clock source based on the real requirement:
* @verbatim embed:rst:leading-asterisk
* +---------------------+-------------------------+----------------------------+
* | LCD clock source | Features | Power Management |
* +=====================+=========================+============================+
* | LCD_CLK_SRC_PLL160M | High resolution | ESP_PM_APB_FREQ_MAX lock |
* +---------------------+-------------------------+----------------------------+
* | LCD_CLK_SRC_PLL240M | High resolution | ESP_PM_APB_FREQ_MAX lock |
* +---------------------+-------------------------+----------------------------+
* | LCD_CLK_SRC_APLL | Configurable resolution | ESP_PM_NO_LIGHT_SLEEP lock |
* +---------------------+-------------------------+----------------------------+
* | LCD_CLK_SRC_XTAL | Medium resolution | No PM lock |
* +---------------------+-------------------------+----------------------------+
* @endverbatim
*/
typedef enum {
LCD_CLK_SRC_PLL160M, /*!< Select PLL160M as the source clock */
LCD_CLK_SRC_PLL240M, /*!< Select PLL240M as the source clock */
LCD_CLK_SRC_APLL, /*!< Select APLL as the source clock */
LCD_CLK_SRC_XTAL, /*!< Select XTAL as the source clock */
} lcd_clock_source_t;
/**
* @brief LCD color space
*/
typedef enum {
LCD_COLOR_SPACE_RGB, /*!< Color space: RGB */
LCD_COLOR_SPACE_YUV, /*!< Color space: YUV */
} lcd_color_space_t;
/**
* @brief LCD color range
*/
typedef enum {
LCD_COLOR_RANGE_LIMIT, /*!< Limited color range */
LCD_COLOR_RANGE_FULL, /*!< Full color range */
} lcd_color_range_t;
/**
* @brief YUV sampling method
*/
typedef enum {
LCD_YUV_SAMPLE_422, /*!< YUV 4:2:2 sampling */
LCD_YUV_SAMPLE_420, /*!< YUV 4:2:0 sampling */
LCD_YUV_SAMPLE_411, /*!< YUV 4:1:1 sampling */
} lcd_yuv_sample_t;
/**
* @brief The standard used for conversion between RGB and YUV
*/
typedef enum {
LCD_YUV_CONV_STD_BT601, /*!< YUV<->RGB conversion standard: BT.601 */
LCD_YUV_CONV_STD_BT709, /*!< YUV<->RGB conversion standard: BT.709 */
} lcd_yuv_conv_std_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,388 @@
// Copyright 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for LEDC.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "hal/ledc_ll.h"
#include "hal/ledc_types.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
ledc_dev_t *dev;
ledc_mode_t speed_mode;
} ledc_hal_context_t;
/**
* @brief Set LEDC low speed timer clock
*
* @param hal Context of the HAL layer
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
#define ledc_hal_set_slow_clk_sel(hal, slow_clk_sel) ledc_ll_set_slow_clk_sel((hal)->dev, slow_clk_sel)
/**
* @brief Get LEDC low speed timer clock
*
* @param hal Context of the HAL layer
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
#define ledc_hal_get_slow_clk_sel(hal, slow_clk_sel) ledc_ll_get_slow_clk_sel((hal)->dev, slow_clk_sel)
/**
* @brief Update LEDC low speed timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_ls_timer_update(hal, timer_sel) ledc_ll_ls_timer_update((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Reset LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_rst(hal, timer_sel) ledc_ll_timer_rst((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Pause LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_pause(hal, timer_sel) ledc_ll_timer_pause((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Resume LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_resume(hal, timer_sel) ledc_ll_timer_resume((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Set LEDC timer clock divider
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
#define ledc_hal_set_clock_divider(hal, timer_sel, clock_divider) ledc_ll_set_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
/**
* @brief Get LEDC timer clock divider
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
#define ledc_hal_get_clock_divider(hal, timer_sel, clock_divider) ledc_ll_get_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
/**
* @brief Set LEDC timer clock source
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @return None
*/
#define ledc_hal_set_clock_source(hal, timer_sel, clk_src) ledc_ll_set_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
/**
* @brief Get LEDC timer clock source
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Pointer to accept the timer clock source
*
* @return None
*/
#define ledc_hal_get_clock_source(hal, timer_sel, clk_src) ledc_ll_get_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
/**
* @brief Set LEDC duty resolution
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
*
* @return None
*/
#define ledc_hal_set_duty_resolution(hal, timer_sel, duty_resolution) ledc_ll_set_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
/**
* @brief Get LEDC duty resolution
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
*
* @return None
*/
#define ledc_hal_get_duty_resolution(hal, timer_sel, duty_resolution) ledc_ll_get_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
/**
* @brief Get LEDC max duty
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param max_duty Pointer to accept the max duty
*
* @return None
*/
#define ledc_hal_get_max_duty(hal, channel_num, max_duty) ledc_ll_get_max_duty((hal)->dev, (hal)->speed_mode, channel_num, max_duty)
/**
* @brief Get LEDC hpoint value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
#define ledc_hal_get_hpoint(hal, channel_num, hpoint_val) ledc_ll_get_hpoint((hal)->dev, (hal)->speed_mode, channel_num, hpoint_val)
/**
* @brief Set LEDC the integer part of duty value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
*
* @return None
*/
#define ledc_hal_set_duty_int_part(hal, channel_num, duty_val) ledc_ll_set_duty_int_part((hal)->dev, (hal)->speed_mode, channel_num, duty_val)
/**
* @brief Set the output enable
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param sig_out_en The output enable status
*
* @return None
*/
#define ledc_hal_set_sig_out_en(hal, channel_num, sig_out_en) ledc_ll_set_sig_out_en((hal)->dev, (hal)->speed_mode, channel_num, sig_out_en)
/**
* @brief Set the duty start
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_start The duty start
*
* @return None
*/
#define ledc_hal_set_duty_start(hal, channel_num, duty_start) ledc_ll_set_duty_start((hal)->dev, (hal)->speed_mode, channel_num, duty_start)
/**
* @brief Set output idle level
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param idle_level The output idle level
*
* @return None
*/
#define ledc_hal_set_idle_level(hal, channel_num, idle_level) ledc_ll_set_idle_level((hal)->dev, (hal)->speed_mode, channel_num, idle_level)
/**
* @brief Set fade end interrupt enable
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param fade_end_intr_en The fade end interrupt enable status
*
* @return None
*/
#define ledc_hal_set_fade_end_intr(hal, channel_num, fade_end_intr_en) ledc_ll_set_fade_end_intr((hal)->dev, (hal)->speed_mode, channel_num, fade_end_intr_en)
/**
* @brief Set timer index of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_bind_channel_timer(hal, channel_num, timer_sel) ledc_ll_bind_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
/**
* @brief Get timer index of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel Pointer to accept the LEDC timer index
*
* @return None
*/
#define ledc_hal_get_channel_timer(hal, channel_num, timer_sel) ledc_ll_get_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
/**
* @brief Init the LEDC hal. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param speed_mode speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mod
*
* @return None
*/
void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode);
/**
* @brief Update channel configure when select low speed mode
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
void ledc_hal_ls_channel_update(ledc_hal_context_t *hal, ledc_channel_t channel_num);
/**
* @brief Set LEDC hpoint value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
void ledc_hal_set_hpoint(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t hpoint_val);
/**
* @brief Get LEDC duty value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val Pointer to accept the LEDC duty value
*
* @return None
*/
void ledc_hal_get_duty(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t *duty_val);
/**
* @brief Set LEDC duty change direction
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction LEDC duty change direction, increase or decrease
*
* @return None
*/
void ledc_hal_set_duty_direction(ledc_hal_context_t *hal, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction);
/**
* @brief Set the number of increased or decreased times
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_num The number of increased or decreased times
*
* @return None
*/
void ledc_hal_set_duty_num(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_num);
/**
* @brief Set the duty cycles of increase or decrease
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_cycle The duty cycles
*
* @return None
*/
void ledc_hal_set_duty_cycle(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_cycle);
/**
* @brief Set the step scale of increase or decrease
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_scale The step scale
*
* @return None
*/
void ledc_hal_set_duty_scale(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_scale);
/**
* @brief Get interrupt status of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param intr_status Pointer to accept the interrupt status
*
* @return None
*/
void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status);
/**
* @brief Clear interrupt status of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num);
/**
* @brief Get clock config of LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_cfg Pointer to accept clock config
*
* @return None
*/
void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg);
/**
* @brief Config low speed timer clock source with clock config
*s
* @param hal Context of the HAL layer
* @param clk_cfg clock config
*
* @return None
*/
void ledc_hal_set_slow_clk(ledc_hal_context_t *hal, ledc_clk_cfg_t clk_cfg);

View File

@@ -0,0 +1,130 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
typedef enum {
#if SOC_LEDC_SUPPORT_HS_MODE
LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
#endif
LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */
LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */
} ledc_mode_t;
typedef enum {
LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */
LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */
LEDC_INTR_MAX,
} ledc_intr_type_t;
typedef enum {
LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */
LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */
LEDC_DUTY_DIR_MAX,
} ledc_duty_direction_t;
typedef enum {
LEDC_SLOW_CLK_RTC8M = 0, /*!< LEDC low speed timer clock source is 8MHz RTC clock*/
LEDC_SLOW_CLK_APB, /*!< LEDC low speed timer clock source is 80MHz APB clock*/
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
LEDC_SLOW_CLK_XTAL, /*!< LEDC low speed timer clock source XTAL clock*/
#endif
} ledc_slow_clk_sel_t;
/**
* In theory, the following enumeration shall be placed in LEDC driver's header.
* However, as the next enumeration, `ledc_clk_src_t`, makes the use of some of
* these values and to avoid mutual inclusion of the headers, we must define it
* here.
*/
typedef enum {
LEDC_AUTO_CLK = 0, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/
LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/
LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/
#if SOC_LEDC_SUPPORT_REF_TICK
LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/
#endif
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
LEDC_USE_XTAL_CLK, /*!< LEDC timer select XTAL clock as source clock*/
#endif
} ledc_clk_cfg_t;
/* Note: Setting numeric values to match ledc_clk_cfg_t values are a hack to avoid collision with
LEDC_AUTO_CLK in the driver, as these enums have very similar names and user may pass
one of these by mistake. */
typedef enum {
#if SOC_LEDC_SUPPORT_REF_TICK
LEDC_REF_TICK = LEDC_USE_REF_TICK, /*!< LEDC timer clock divided from reference tick (1Mhz) */
#endif
LEDC_APB_CLK = LEDC_USE_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */
LEDC_SCLK = LEDC_USE_APB_CLK /*!< Selecting this value for LEDC_TICK_SEL_TIMER let the hardware take its source clock from LEDC_APB_CLK_SEL */
} ledc_clk_src_t;
typedef enum {
LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */
LEDC_TIMER_1, /*!< LEDC timer 1 */
LEDC_TIMER_2, /*!< LEDC timer 2 */
LEDC_TIMER_3, /*!< LEDC timer 3 */
LEDC_TIMER_MAX,
} ledc_timer_t;
typedef enum {
LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
LEDC_CHANNEL_1, /*!< LEDC channel 1 */
LEDC_CHANNEL_2, /*!< LEDC channel 2 */
LEDC_CHANNEL_3, /*!< LEDC channel 3 */
LEDC_CHANNEL_4, /*!< LEDC channel 4 */
LEDC_CHANNEL_5, /*!< LEDC channel 5 */
#if SOC_LEDC_CHANNEL_NUM > 6
LEDC_CHANNEL_6, /*!< LEDC channel 6 */
LEDC_CHANNEL_7, /*!< LEDC channel 7 */
#endif
LEDC_CHANNEL_MAX,
} ledc_channel_t;
typedef enum {
LEDC_TIMER_1_BIT = 1, /*!< LEDC PWM duty resolution of 1 bits */
LEDC_TIMER_2_BIT, /*!< LEDC PWM duty resolution of 2 bits */
LEDC_TIMER_3_BIT, /*!< LEDC PWM duty resolution of 3 bits */
LEDC_TIMER_4_BIT, /*!< LEDC PWM duty resolution of 4 bits */
LEDC_TIMER_5_BIT, /*!< LEDC PWM duty resolution of 5 bits */
LEDC_TIMER_6_BIT, /*!< LEDC PWM duty resolution of 6 bits */
LEDC_TIMER_7_BIT, /*!< LEDC PWM duty resolution of 7 bits */
LEDC_TIMER_8_BIT, /*!< LEDC PWM duty resolution of 8 bits */
LEDC_TIMER_9_BIT, /*!< LEDC PWM duty resolution of 9 bits */
LEDC_TIMER_10_BIT, /*!< LEDC PWM duty resolution of 10 bits */
LEDC_TIMER_11_BIT, /*!< LEDC PWM duty resolution of 11 bits */
LEDC_TIMER_12_BIT, /*!< LEDC PWM duty resolution of 12 bits */
LEDC_TIMER_13_BIT, /*!< LEDC PWM duty resolution of 13 bits */
LEDC_TIMER_14_BIT, /*!< LEDC PWM duty resolution of 14 bits */
#if SOC_LEDC_TIMER_BIT_WIDE_NUM > 14
LEDC_TIMER_15_BIT, /*!< LEDC PWM duty resolution of 15 bits */
LEDC_TIMER_16_BIT, /*!< LEDC PWM duty resolution of 16 bits */
LEDC_TIMER_17_BIT, /*!< LEDC PWM duty resolution of 17 bits */
LEDC_TIMER_18_BIT, /*!< LEDC PWM duty resolution of 18 bits */
LEDC_TIMER_19_BIT, /*!< LEDC PWM duty resolution of 19 bits */
LEDC_TIMER_20_BIT, /*!< LEDC PWM duty resolution of 20 bits */
#endif
LEDC_TIMER_BIT_MAX,
} ledc_timer_bit_t;
typedef enum {
LEDC_FADE_NO_WAIT = 0, /*!< LEDC fade function will return immediately */
LEDC_FADE_WAIT_DONE, /*!< LEDC fade function will block until fading to the target duty */
LEDC_FADE_MAX,
} ledc_fade_mode_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,41 @@
// Copyright 2015-2021 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for MCPWM (common part)
#pragma once
#include "soc/mcpwm_struct.h"
typedef struct {
int host_id; ///< Which MCPWM peripheral to use, 0-1.
} mcpwm_hal_init_config_t;
typedef struct {
mcpwm_dev_t *dev; ///< Beginning address of the peripheral registers of a single MCPWM unit. Call `mcpwm_hal_init` to initialize it.
} mcpwm_hal_context_t;
/**
* @brief Initialize the internal state of the HAL.
*
* @param hal Context of the HAL layer.
* @param init_config Configuration for the HAL to be used only once.
*/
void mcpwm_hal_init(mcpwm_hal_context_t *hal, const mcpwm_hal_init_config_t *init_config);

View File

@@ -0,0 +1,52 @@
// Copyright 2015-2021 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.
#pragma once
typedef enum {
MCPWM_TIMER_DIRECTION_UP, /*!< Counting direction: Increase */
MCPWM_TIMER_DIRECTION_DOWN, /*!< Counting direction: Decrease */
} mcpwm_timer_direction_t;
typedef enum {
MCPWM_TIMER_EVENT_ZERO, /*!< MCPWM timer counts to zero */
MCPWM_TIMER_EVENT_PEAK, /*!< MCPWM timer counts to peak */
} mcpwm_timer_event_t;
typedef enum {
MCPWM_TIMER_COUNT_MODE_PAUSE, /*!< MCPWM timer paused */
MCPWM_TIMER_COUNT_MODE_UP, /*!< MCPWM timer counting up */
MCPWM_TIMER_COUNT_MODE_DOWN, /*!< MCPWM timer counting down */
MCPWM_TIMER_COUNT_MODE_UP_DOWN, /*!< MCPWM timer counting up and down */
} mcpwm_timer_count_mode_t;
typedef enum {
MCPWM_TIMER_STOP_AT_ZERO, /*!< MCPWM timer stops when couting to zero */
MCPWM_TIMER_STOP_AT_PEAK, /*!< MCPWM timer stops when counting to peak */
MCPWM_TIMER_START_NO_STOP, /*!< MCPWM timer starts couting */
MCPWM_TIMER_START_STOP_AT_ZERO, /*!< MCPWM timer starts counting and stops when couting to zero */
MCPWM_TIMER_START_STOP_AT_PEAK, /*!< MCPWM timer starts counting and stops when counting to peak */
} mcpwm_timer_execute_cmd_t;
typedef enum {
MCPWM_GEN_ACTION_KEEP, /*!< Generator action: Keep the same level */
MCPWM_GEN_ACTION_LOW, /*!< Generator action: Force to low level */
MCPWM_GEN_ACTION_HIGH, /*!< Generator action: Force to high level */
MCPWM_GEN_ACTION_TOGGLE, /*!< Generator action: Toggle level */
} mcpwm_generator_action_t;
typedef enum {
MCPWM_TRIP_TYPE_CBC, /*!< CBC trip type, shut down the operator cycle by cycle*/
MCPWM_TRIP_TYPE_OST, /*!< OST trip type, shut down the operator in one shot */
} mcpwm_trip_type_t;

View File

@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Memprot LL error codes
*
*/
typedef enum {
MEMP_LL_OK = 0,
MEMP_LL_FAIL = 1,
MEMP_LL_ERR_SPLIT_ADDR_OUT_OF_RANGE = 2,
MEMP_LL_ERR_SPLIT_ADDR_INVALID = 2, /* temporary duplicate for S2 builds */
MEMP_LL_ERR_SPLIT_ADDR_UNALIGNED = 3,
MEMP_LL_ERR_UNI_BLOCK_INVALID = 4,
MEMP_LL_ERR_AREA_INVALID = 5,
MEMP_LL_ERR_WORLD_INVALID = 6
} memprot_ll_err_t;
/**
* @brief Memprot LL PMS World IDs
*
*/
typedef enum {
MEMP_LL_WORLD_NONE = 0x00,
MEMP_LL_WORLD_0 = 0x01,
MEMP_LL_WORLD_1 = 0x10
} memprot_ll_world_t;
/**
* @brief Memprot LL PMS Area IDs
*
*/
typedef enum {
MEMP_LL_AREA_NONE = 0,
MEMP_LL_AREA_LOW = 1,
MEMP_LL_AREA_HIGH = 2
} memprot_ll_area_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,36 @@
// 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.
#include <stdint.h>
#include "esp_err.h"
#include "hal/mpu_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Specify the type of access allowed on a memory region.
*
* @param id index to the region table; on targets not SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED,
* the region divisions is predefined in hardware which is likely reflected in LL implementation.
* @param access type of access allowed
*/
void mpu_hal_set_region_access(int id, mpu_access_t access);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,34 @@
// 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.
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED
typedef void** mpu_region_table_t;
#endif
typedef enum {
MPU_REGION_ILLEGAL,
#if SOC_MPU_REGION_RO_SUPPORTED
MPU_REGION_RO, // read-only
#endif
#if SOC_MPU_REGION_WO_SUPPORTED
MPU_REGION_WO, // write-only
#endif
MPU_REGION_RW, // read-write
MPU_REGION_X, // executable
MPU_REGION_RWX // read-write-executable
} mpu_access_t;

View File

@@ -0,0 +1,50 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for PCNT.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/pcnt_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
pcnt_dev_t *dev; /*!< PCNT peripheral register base address */
} pcnt_hal_context_t;
/**
* @brief Init the PCNT hal and set the PCNT to the default configuration.
* @note This function should be called first before other hal layer function is called.
*
* @param hal Context of the HAL layer
* @param group_id PCNT group ID
*/
void pcnt_hal_init(pcnt_hal_context_t *hal, int group_id);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,54 @@
// Copyright 2015-2021 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief PCNT channel action on control level
*
*/
typedef enum {
PCNT_CHANNEL_LEVEL_ACTION_KEEP, /*!< Keep current count mode */
PCNT_CHANNEL_LEVEL_ACTION_INVERSE, /*!< Invert current count mode (increase -> decrease, decrease -> increase) */
PCNT_CHANNEL_LEVEL_ACTION_HOLD, /*!< Hold current count value */
} pcnt_channel_level_action_t;
/**
* @brief PCNT channel action on signal edge
*
*/
typedef enum {
PCNT_CHANNEL_EDGE_ACTION_HOLD, /*!< Hold current count value */
PCNT_CHANNEL_EDGE_ACTION_INCREASE, /*!< Increase count value */
PCNT_CHANNEL_EDGE_ACTION_DECREASE, /*!< Decrease count value */
} pcnt_channel_edge_action_t;
/**
* @brief PCNT unit counter value's sign
*
*/
typedef enum {
PCNT_UNIT_COUNT_SIGN_ZERO_POS, /*!< positive value to zero */
PCNT_UNIT_COUNT_SIGN_ZERO_NEG, /*!< negative value to zero */
PCNT_UNIT_COUNT_SIGN_NEG, /*!< counter value negative */
PCNT_UNIT_COUNT_SIGN_POS, /*!< counter value positive */
} pcnt_unit_count_sign_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,112 @@
// Copyright 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "soc/soc_caps.h"
#include "soc/rmt_struct.h"
/**
* @brief HAL context type of RMT driver
*
*/
typedef struct {
rmt_dev_t *regs; /*!< RMT Register base address */
rmt_mem_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
*
* @param hal: RMT HAL context
*/
void rmt_hal_init(rmt_hal_context_t *hal);
/**
* @brief Reset RMT TX Channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
*/
void rmt_hal_tx_channel_reset(rmt_hal_context_t *hal, uint32_t channel);
/**
* @brief Reset RMT TX Channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
*/
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);
/**
* @brief Receive a frame from RMT channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param buf: buffer to store received RMT frame
* @return number of items that get received
*/
uint32_t rmt_hal_receive(rmt_hal_context_t *hal, uint32_t channel, rmt_item32_t *buf);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,127 @@
// 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.
#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
*
*/
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;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,94 @@
// 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.
#pragma once
#include "soc/soc_caps.h"
#include "hal/gpio_types.h"
#include "hal/rtc_cntl_ll.h"
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
#include "hal/rtc_io_ll.h"
#endif
typedef struct rtc_cntl_sleep_retent {
#if SOC_PM_SUPPORT_CPU_PD
void *cpu_pd_mem; /* Internal ram address for cpu retention */
#endif // SOC_PM_SUPPORT_CPU_PD
#if SOC_PM_SUPPORT_TAGMEM_PD
struct {
void *link_addr; /* Internal ram address for tagmem retention */
struct {
uint32_t start_point: 8, /* the row of start for i-cache tag memory */
vld_size: 8, /* valid size of i-cache tag memory, unit: 4 i-cache tagmem blocks */
size: 8, /* i-cache tag memory size, unit: 4 i-cache tagmem blocks */
enable: 1; /* enable or disable i-cache tagmem retention */
} icache;
struct {
uint32_t start_point: 9, /* the row of start for d-cache tag memory */
vld_size: 9, /* valid size of d-cache tag memory, unit: 4 d-cache tagmem blocks */
size: 9, /* d-cache tag memory size, unit: 4 d-cache tagmem blocks */
enable: 1; /* enable or disable d-cache tagmem retention */
} dcache;
} tagmem;
#endif // SOC_PM_SUPPORT_TAGMEM_PD
} rtc_cntl_sleep_retent_t;
#define RTC_HAL_DMA_LINK_NODE_SIZE (16)
#if SOC_PM_SUPPORT_EXT_WAKEUP
#define rtc_hal_ext1_get_wakeup_pins() rtc_cntl_ll_ext1_get_wakeup_pins()
#define rtc_hal_ext1_set_wakeup_pins(mask, mode) rtc_cntl_ll_ext1_set_wakeup_pins(mask, mode)
#define rtc_hal_ext1_clear_wakeup_pins() rtc_cntl_ll_ext1_clear_wakeup_pins()
#endif
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#define rtc_hal_gpio_get_wakeup_pins() rtc_cntl_ll_gpio_get_wakeup_pins()
#define rtc_hal_gpio_clear_wakeup_pins() rtc_cntl_ll_gpio_clear_wakeup_pins()
#define rtc_hal_gpio_set_wakeup_pins() rtc_cntl_ll_gpio_set_wakeup_pins()
#endif
#define rtc_hal_set_wakeup_timer(ticks) rtc_cntl_ll_set_wakeup_timer(ticks)
void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next);
#if SOC_PM_SUPPORT_CPU_PD
void rtc_cntl_hal_enable_cpu_retention(void *addr);
void rtc_cntl_hal_disable_cpu_retention(void *addr);
#endif
#if SOC_PM_SUPPORT_TAGMEM_PD
void rtc_cntl_hal_enable_tagmem_retention(void *addr);
void rtc_cntl_hal_disable_tagmem_retention(void *addr);
#endif
/*
* Enable wakeup from ULP coprocessor.
*/
#define rtc_hal_ulp_wakeup_enable() rtc_cntl_ll_ulp_wakeup_enable()
#define rtc_hal_ulp_int_clear() rtc_cntl_ll_ulp_int_clear()

View File

@@ -0,0 +1,264 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for RTC IO master (common part)
#pragma once
#include <esp_err.h>
#if !CONFIG_IDF_TARGET_ESP32C3 && !CONFIG_IDF_TARGET_ESP32H2
#include "soc/soc_caps.h"
#include "hal/rtc_io_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
/**
* Select the rtcio function.
*
* @note The RTC function must be selected before the pad analog function is enabled.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param func Select pin function.
*/
#define rtcio_hal_function_select(rtcio_num, func) rtcio_ll_function_select(rtcio_num, func)
/**
* Enable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_output_enable(rtcio_num) rtcio_ll_output_enable(rtcio_num)
/**
* Disable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_output_disable(rtcio_num) rtcio_ll_output_disable(rtcio_num)
/**
* Set RTCIO output level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level 0: output low; ~0: output high.
*/
#define rtcio_hal_set_level(rtcio_num, level) rtcio_ll_set_level(rtcio_num, level)
/**
* Enable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_input_enable(rtcio_num) rtcio_ll_input_enable(rtcio_num)
/**
* Disable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_input_disable(rtcio_num) rtcio_ll_input_disable(rtcio_num)
/**
* Get RTCIO input level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return 0: input low; ~0: input high.
*/
#define rtcio_hal_get_level(rtcio_num) rtcio_ll_get_level(rtcio_num)
/**
* @brief Set RTC GPIO pad drive capability.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param strength Drive capability of the pad. Range: 0 ~ 3.
*/
#define rtcio_hal_set_drive_capability(rtcio_num, strength) rtcio_ll_set_drive_capability(rtcio_num, strength)
/**
* @brief Get RTC GPIO pad drive capability.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return Drive capability of the pad. Range: 0 ~ 3.
*/
#define rtcio_hal_get_drive_capability(rtcio_num) rtcio_ll_get_drive_capability(rtcio_num)
/**
* Set RTCIO output level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level 0: output low; ~0: output high.
*/
#define rtcio_hal_set_level(rtcio_num, level) rtcio_ll_set_level(rtcio_num, level)
/**
* Get RTCIO input level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return 0: input low; ~0: input high.
*/
#define rtcio_hal_get_level(rtcio_num) rtcio_ll_get_level(rtcio_num)
/**
* Set RTC IO direction.
*
* Configure RTC IO direction, such as output only, input only,
* output and input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param mode IO direction.
*/
void rtcio_hal_set_direction(int rtcio_num, rtc_gpio_mode_t mode);
/**
* Set RTC IO direction in deep sleep or disable sleep status.
*
* NOTE: ESP32 support INPUT_ONLY mode.
* ESP32S2 support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param mode IO direction.
*/
void rtcio_hal_set_direction_in_sleep(int rtcio_num, rtc_gpio_mode_t mode);
/**
* RTC GPIO pullup enable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pullup_enable(rtcio_num) rtcio_ll_pullup_enable(rtcio_num)
/**
* RTC GPIO pullup disable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pullup_disable(rtcio_num) rtcio_ll_pullup_disable(rtcio_num)
/**
* RTC GPIO pulldown enable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pulldown_enable(rtcio_num) rtcio_ll_pulldown_enable(rtcio_num)
/**
* RTC GPIO pulldown disable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pulldown_disable(rtcio_num) rtcio_ll_pulldown_disable(rtcio_num)
#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
#if SOC_RTCIO_HOLD_SUPPORTED
/**
* Enable force hold function for RTC IO pad.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_enable(rtcio_num) rtcio_ll_force_hold_enable(rtcio_num)
/**
* Disable hold function on an RTC IO pad
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_disable(rtcio_num) rtcio_ll_force_hold_disable(rtcio_num)
/**
* Enable force hold function for RTC IO pads.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_all() rtcio_ll_force_hold_all()
/**
* Disable hold function on an RTC IO pads.
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_unhold_all() rtcio_ll_force_unhold_all()
#endif // SOC_RTCIO_HOLD_SUPPORTED
#if SOC_RTCIO_WAKE_SUPPORTED
/**
* Enable wakeup function and set wakeup type from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param type Wakeup on high level or low level.
*/
#define rtcio_hal_wakeup_enable(rtcio_num, type) rtcio_ll_wakeup_enable(rtcio_num, type)
/**
* Disable wakeup function from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_wakeup_disable(rtcio_num) rtcio_ll_wakeup_disable(rtcio_num)
/**
* Set specific logic level on an RTC IO pin as a wakeup trigger.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level Logic level (0)
*/
#define rtcio_hal_ext0_set_wakeup_pin(rtcio_num, level) rtcio_ll_ext0_set_wakeup_pin(rtcio_num, level)
#endif
#if SOC_RTCIO_HOLD_SUPPORTED || SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
/**
* Helper function to disconnect internal circuits from an RTC IO
* This function disables input, output, pullup, pulldown, and enables
* hold feature for an RTC IO.
* Use this function if an RTC IO needs to be disconnected from internal
* circuits in deep sleep, to minimize leakage current.
*
* In particular, for ESP32-WROVER module, call
* rtc_gpio_isolate(GPIO_NUM_12) before entering deep sleep, to reduce
* deep sleep current.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
void rtcio_hal_isolate(int rtc_num);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,25 @@
// Copyright 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.
#pragma once
/** RTCIO output/input mode type. */
typedef enum {
RTC_GPIO_MODE_INPUT_ONLY , /*!< Pad input */
RTC_GPIO_MODE_OUTPUT_ONLY, /*!< Pad output */
RTC_GPIO_MODE_INPUT_OUTPUT, /*!< Pad input + output */
RTC_GPIO_MODE_DISABLED, /*!< Pad (output + input) disable */
RTC_GPIO_MODE_OUTPUT_OD, /*!< Pad open-drain output */
RTC_GPIO_MODE_INPUT_OUTPUT_OD, /*!< Pad input + open-drain output */
} rtc_gpio_mode_t;

View File

@@ -0,0 +1,528 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SDIO slave (common part)
// SDIO slave HAL usages:
/*
Architecture:
The whole SDIO slave peripheral consists of three parts: the registers (including the interrupt
control and shared registers), a send FIFO, and a receive FIFO. The document
``esp_slave_protocol.rst`` describes the functionality of the peripheral in detail. An SDIO host
will only ever access one of the three parts at any one time, thus the hardware functionality of
the SDIO slave peripheral are completely independent. Likewise, this HAL is organized in such a
fashion as to correspond to the three independent parts.
The shared registers are quite simple: the slave can directly access them from the internal data
bus, while the host can access them by CMD52/53 with the correct address. As for the interrupts:
when an SDIO host interrupts the SDIO slave peripheral (by writing a command), the corresponding
bit in the interrupt register will be set; when the SDIO slave peripheral needs to interrupt the
host, it write some register to cause the host interrupt bit being set, and the slave hardware
will output the interrupt signal on the DAT1 line.
For the FIFOs, the peripheral provides counters as registers so that the host can always know whether the slave
is ready to send/receive data. The HAL resets the counters during initialization, and the host should somehow
inform the slave to reset the counters again if it should reboot (or lose the counter value for some reasons).
Then the host can read/write the FIFOs by CMD53 commands according to the counters.
In order to avoid copying data to/from the FIFOs or memory buffers each time, the HAL layer
contains a descriptor queue (implemented as linked-list) that allows descriptors of memory
buffers to be queued for transmission/reception. Once a buffer is queued, the HAL takes ownership
of the buffer until some "finish" functions successfully return, indicating the
transmission/reception of that buffer is complete. The ISR is invoked multiple times to iterate
through the queued descriptors, and also to signal to the upper layer if a buffer has been
freed.
The HAL is used as below:
- Receiving part:
1. Call `sdio_slave_hal_recv_start` to start the receiving DMA.
If there are already buffers loaded, the receiving will start from those buffers first.
2. Call `sdio_slave_hal_recv_init_desc` with a `sdio_slave_hal_recv_desc_t` and the buffer address to
associate the descriptor with the buffer.
The HAL initialize this descriptors with the determined length and maybe some extra data.
3. Call `sdio_slave_hal_load_buf` with the initialized descriptor of the buffer to load a
receiving buffer to the HAL.
When the DMA is started, the descriptors is loaded onto the DMA linked-list, and the
counter of receiving buffers is increased so that the host will know this by the
receiving interrupt. The hardware will automatically go through the linked list and write
data into the buffers loaded on the list.
4. (Optional, mandatory only when interrupt enabled) Call `sdio_slave_hal_recv_done` to check
and clear the receiving interrupt bits.
5. Call `sdio_slave_hal_recv_has_next_item` to check whether there are finished buffers.
6. Call `sdio_slave_hal_recv_unload_desc` for the same times as
`sdio_slave_hal_recv_has_next_item` successfully returns.
7. (Optional) Call `sdio_slave_hal_recv_reset_counter` to reset the counter to current loaded
but not used buffers if you want to reset the counter only. This is available only when
the DMA is stopped.
8. (Optional) Call `sdio_slave_hal_recv_flush_one_buffer` (recursively) if you want to
discard data of one (or more) buffers and load them again. This is available only when
the DMA is stopped.
9. (Optional when deinitialization) Call `sdio_slave_hal_recv_unload_desc` recursively to get
all the buffers loaded to the HAL, no matter they are used or not. Don't do this when the
DMA is not stopped.
- Sending part:
The sending driver is slightly different, since we are not using the re-start feature.
(TODO: re-write this part if the stitch mode is released)
1. Call `sdio_slave_hal_send_start` to start the sending DMA.
If there is already any data queued, it will ne ready to be sent to host now.
2. Call `sdio_slave_hal_send_queue` to queue the data to send.
If the interrupt is enabled, the ISR will be invoked.
3. (Required if interrupt enabled) Call `` to clear the interrupt bits used by the SW
invoking logic.
4. Call `sdio_slave_hal_send_new_packet_if_exist` to check and send new packet (if there is
data queued).
5. Call `sdio_slave_hal_send_eof_happened` to check whether the previous packet is done.
It will also clear the interrupt status bit for this event.
6. Call `sdio_slave_hal_send_get_next_finished_arg` recursively to get the arguments for the
finished buffers.
7. (Optional when deinitialization) Call `sdio_slave_hal_send_flush_next_buffer` recursively
to get all buffers queued, regardless sent or not. Don't do this when the DMA is not stopped.
8. (Optional) Call `sdio_slave_hal_send_reset_counter` to reset the counter to current loaded
but not sent buffers if you want to reset the counter only. Don't do this when the DMA is not
stopped.
Note a counter should be used when performing step 2 and 6, to make sure that the queue size
is enough.
- Host part:
1. Call `sdio_slave_hal_hostint_set_ena` and `sdio_slave_hal_hostint_get_ena` to
enable/disable the interrupt sent to master. Note that the host can also modify the same
registers at the same time. Try to avoid using them outside the initialization process.
2. Call `sdio_slave_hal_hostint_send` and `sdio_slave_hal_hostint_clear` to trigger general
purpose interrupts or cancel all kinds of interrupts send to the host. These interrupts are
set/cleared in a concurrent-safe way, so the slave can call these functions safely.
3. Call `sdio_slave_hal_slvint_fetch_clear` to fetch the general purpose interrupts sent by
the host to the slave. These interrupts will also be cleared after the calls.
4. Call `sdio_slave_hal_host_get_reg` and `sdio_slave_hal_host_set_reg` to read/write the
general purpose shared between the host and slave. Note that these registers are also not
concurrent-safe. Try not to write to the same register from two directions at the same time.
*/
#pragma once
#include <esp_err.h>
#include "soc/lldesc.h"
#include "hal/sdio_slave_types.h"
#include "hal/sdio_slave_ll.h"
/// Space used for each sending descriptor. Should initialize the sendbuf accoring to this size.
#define SDIO_SLAVE_SEND_DESC_SIZE sizeof(sdio_slave_hal_send_desc_t)
/// Status of the sending part
typedef enum {
STATE_IDLE = 1,
STATE_WAIT_FOR_START = 2,
STATE_SENDING = 3,
STATE_GETTING_RESULT = 4,
STATE_GETTING_UNSENT_DESC = 5,
} send_state_t;
typedef struct {
uint8_t* data; ///< Address of the buffer
size_t size; ///< Size of the buffer, but can only queue (size/SDIO_SLAVE_SEND_DESC_SIZE)-1 descriptors
uint8_t* write_ptr;
uint8_t* read_ptr;
uint8_t* free_ptr;
} sdio_ringbuf_t;
// Append two extra words to be used by the HAL.
// Should Initialize the member `data` of `send_desc_queue` of the HAL context
// with size of this desc * N.
/// DMA descriptor with extra fields
typedef struct sdio_slave_hal_send_desc_s {
lldesc_t dma_desc; ///< Used by Hardware, has pointer linking to next desc
uint32_t pkt_len; ///< Accumulated length till this descriptor
void* arg; ///< Holding arguments indicating this buffer */
} sdio_slave_hal_send_desc_t;
/// Descriptor used by the receiving part, call `sdio_slave_hal_recv_init_desc`
/// to initialize it before use.
typedef lldesc_t sdio_slave_hal_recv_desc_t;
#define sdio_slave_hal_recv_desc_s lldesc_s
typedef STAILQ_HEAD(recv_stailq_head_s, sdio_slave_hal_recv_desc_s) sdio_slave_hal_recv_stailq_t;
/** HAL context structure. Call `sdio_slave_hal_init` to initialize it and
* configure required members before actually use the HAL.
*/
typedef struct {
/// Hardware registers for this SDIO slave peripheral, configured by
/// `sdio_slave_hal_init`
struct {
slc_dev_t* slc;
host_dev_t* host;
hinf_dev_t* hinf;
};
sdio_slave_sending_mode_t sending_mode; /**< Sending mode, should be manually configured before using the HAL.
* see `sdio_slave_sending_mode_t`.
*/
sdio_slave_timing_t timing; /**< Timing mode (launch edge and latch edge settings). Should be manually
* configured before using the HAL. `SDIO_SLAVE_TIMING_PSEND_PSAMPLE` is
* recommended by default.
*/
int send_queue_size; /**< Max buffers that can be queued before sending. Should be manually
* configured before using the HAL.
*/
size_t recv_buffer_size; /**< The size of each buffer. The host and slave should share a
* pre-negotiated value. Should be manually configured before using
* the HAL.
*/
sdio_ringbuf_t send_desc_queue; /**< The ring buffer used to hold queued descriptors. Should be manually
* initialized before using the HAL.
*/
//Internal status, no need to touch.
send_state_t send_state; // Current state of sending part.
uint32_t tail_pkt_len; // The accumulated send length of the tail packet.
sdio_slave_hal_send_desc_t* in_flight_head; // The head of linked list in-flight.
sdio_slave_hal_send_desc_t* in_flight_end; // The end of linked list in-flight.
sdio_slave_hal_send_desc_t* in_flight_next; // The header of linked list to be sent next time.
sdio_slave_hal_send_desc_t* returned_desc; // The last returned descriptor
sdio_slave_hal_recv_stailq_t recv_link_list; // Linked list of buffers ready to hold data and the buffers already hold data.
volatile sdio_slave_hal_recv_desc_t* recv_cur_ret; // Next desc to return, NULL if all loaded descriptors are returned.
} sdio_slave_context_t ;
/**
* Initialize the HAL, should provide buffers to the context and configure the
* members before this funciton is called.
*
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_init(sdio_slave_context_t *hal);
/**
* Initialize the SDIO slave peripheral hardware.
*
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_hw_init(sdio_slave_context_t *hal);
/**
* Set the IO ready for host to read.
*
* @param hal Context of the HAL layer.
* @param ready true to tell the host the slave is ready, otherwise false.
*/
void sdio_slave_hal_set_ioready(sdio_slave_context_t *hal, bool ready);
/*---------------------------------------------------------------------------
* Send
*--------------------------------------------------------------------------*/
/**
* The hardware sending DMA starts. If there is existing data, send them.
*
* @param hal Context of the HAL layer.
*/
esp_err_t sdio_slave_hal_send_start(sdio_slave_context_t *hal);
/**
* Stops hardware sending DMA.
*
* @note The data in the queue, as well as the counter are not touched.
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_send_stop(sdio_slave_context_t *hal);
/**
* Put some data into the sending queue.
*
* @note The caller should keeps the buffer, until the `arg` is returned by
* `sdio_slave_hal_send_get_next_finished_arg`.
* @note The caller should count to ensure there is enough space in the queue.
* The initial queue size is sizeof(sendbuf.data)/sizeof(sdio_slave_hal_send_desc_t)-1,
* Will decrease by one when this function successfully returns.
* Released only by `sdio_slave_hal_send_get_next_finished_arg` or
* `sdio_slave_hal_send_flush_next_buffer`.
*
* @note The HAL is not thread-safe. The caller should use a spinlock to ensure
* the `sdio_slave_hal_send_queue` and ... are not called at the same time.
*
* @param hal Context of the HAL layer.
* @param addr Address of data in the memory to send.
* @param len Length of data to send.
* @param arg Argument indicating this sending.
* @return Always ESP_OK.
*/
esp_err_t sdio_slave_hal_send_queue(sdio_slave_context_t *hal, uint8_t *addr, size_t len, void *arg);
/**
* The ISR should call this, to handle the SW invoking event.
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_send_handle_isr_invoke(sdio_slave_context_t *hal);
/**
* Check whether there is no in-flight transactions, and send new packet if there
* is new packets queued.
*
* @param hal Context of the HAL layer.
* @return
* - ESP_OK: The DMA starts to send a new packet.
* - ESP_ERR_NOT_FOUND: No packet waiting to be sent.
* - ESP_ERR_INVALID_STATE: There is packet in-flight.
*/
esp_err_t sdio_slave_hal_send_new_packet_if_exist(sdio_slave_context_t *hal);
/**
* Check whether the sending EOF has happened and clear the interrupt.
*
* Call `sdio_slave_hal_send_get_next_finished_arg` recursively to retrieve arguments of finished
* buffers.
*
* @param hal Context of the HAL layer.
* @return true if happened, otherwise false.
*/
bool sdio_slave_hal_send_eof_happened(sdio_slave_context_t *hal);
/**
* Get the arguments of finished packets. Call recursively until all finished
* arguments are all retrieved.
*
* @param hal Context of the HAL layer.
* @param out_arg Output argument of the finished buffer.
* @param out_returned_cnt Released queue size to be queued again.
* @return
* - ESP_OK: if one argument retrieved.
* - ESP_ERR_NOT_FOUND: All the arguments of the finished buffers are retrieved.
*/
esp_err_t sdio_slave_hal_send_get_next_finished_arg(sdio_slave_context_t *hal, void **out_arg, uint32_t* out_returned_cnt);
/**
* Flush one buffer in the queue, no matter sent, canceled or not sent yet.
*
* Call recursively to clear the whole queue before deinitialization.
*
* @note Only call when the DMA is stopped!
* @param hal Context of the HAL layer.
* @param out_arg Argument indiciating the buffer to send
* @param out_return_cnt Space in the queue released after this descriptor is flushed.
* @return
* - ESP_ERR_INVALID_STATE: This function call be called only when the DMA is stopped.
* - ESP_ERR_NOT_FOUND: if no buffer in the queue
* - ESP_OK: if a buffer is successfully flushed and returned.
*/
esp_err_t sdio_slave_hal_send_flush_next_buffer(sdio_slave_context_t *hal, void **out_arg, uint32_t *out_return_cnt);
/**
* Walk through all the unsent buffers and reset the counter to the accumulated length of them. The data will be kept.
*
* @note Only call when the DMA is stopped!
* @param hal Context of the HAL layer.
* @return
* - ESP_ERR_INVALID_STATE: this function call be called only when the DMA is stopped
* - ESP_OK: if success
*/
esp_err_t sdio_slave_hal_send_reset_counter(sdio_slave_context_t *hal);
/*---------------------------------------------------------------------------
* Receive
*--------------------------------------------------------------------------*/
/**
* Start the receiving DMA.
*
* @note If there are already some buffers loaded, will receive from them first.
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_recv_start(sdio_slave_context_t *hal);
/**
* Stop the receiving DMA.
*
* @note Data and the counter will not be touched. You can still call
* `sdio_slave_hal_recv_has_next_item` to get the received buffer.
* And unused buffers loaded to the HAL will still be in the `loaded`
* state in the HAL, until returned by `sdio_slave_hal_recv_unload_desc`.
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_recv_stop(sdio_slave_context_t* hal);
/**
* Associate the buffer to the descriptor given. The descriptor may also be initialized with some
* other data.
*
* @param hal Context of the HAL layer.
* @param desc Descriptor to associate with the buffer
* @param start Start address of the buffer
*/
void sdio_slave_hal_recv_init_desc(sdio_slave_context_t *hal, sdio_slave_hal_recv_desc_t *desc, uint8_t *start);
/**
* Load the buffer to the HAL to be used to receive data.
*
* @note Loaded buffers will be returned to the upper layer only when:
* 1. Returned by `sdio_slave_hal_recv_has_next_item` when receiving to that buffer successfully
* done.
* 2. Returned by `sdio_slave_hal_recv_unload_desc` unconditionally.
* @param hal Context of the HAL layer.
* @param desc Descriptor to load to the HAL to receive.
*/
void sdio_slave_hal_load_buf(sdio_slave_context_t *hal, sdio_slave_hal_recv_desc_t *desc);
/**
* Check and clear the interrupt indicating a buffer has finished receiving.
*
* @param hal Context of the HAL layer.
* @return true if interrupt triggered, otherwise false.
*/
bool sdio_slave_hal_recv_done(sdio_slave_context_t* hal);
/**
* Call this function recursively to check whether there is any buffer that has
* finished receiving.
*
* Will walk through the linked list to find a newer finished buffer. For each successful return,
* it means there is one finished buffer. You can one by `sdio_slave_hal_recv_unload_desc`. You can
* also call `sdio_slave_hal_recv_has_next_item` several times continuously before you call the
* `sdio_slave_hal_recv_unload_desc` for the same times.
*
* @param hal Context of the HAL layer.
* @return true if there is
*/
bool sdio_slave_hal_recv_has_next_item(sdio_slave_context_t* hal);
/**
* Unconditionally remove and return the first descriptor loaded to the HAL.
*
* Unless during de-initialization, `sdio_slave_hal_recv_has_next_item` should have succeed for the
* same times as this function is called, to ensure the returned descriptor has finished its
* receiving job.
*
* @param hal Context of the HAL layer.
* @return The removed descriptor, NULL means the linked-list is empty.
*/
sdio_slave_hal_recv_desc_t *sdio_slave_hal_recv_unload_desc(sdio_slave_context_t *hal);
/**
* Walk through all the unused buffers and reset the counter to the number of
* them.
*
* @note Only call when the DMA is stopped!
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_recv_reset_counter(sdio_slave_context_t *hal);
/**
* Walk through all the used buffers, clear the finished flag and appended them
* back to the end of the unused list, waiting to receive then.
*
* @note You will lose all the received data in the buffer.
* @note Only call when the DMA is stopped!
* @param hal Context of the HAL layer.
*/
void sdio_slave_hal_recv_flush_one_buffer(sdio_slave_context_t *hal);
/*---------------------------------------------------------------------------
* Host
*--------------------------------------------------------------------------*/
/**
* Enable some of the interrupts for the host.
*
* @note May have concurrency issue wit the host or other tasks, suggest only use it during
* initialization.
* @param hal Context of the HAL layer.
* @param mask Bitwise mask for the interrupts to enable.
*/
void sdio_slave_hal_hostint_set_ena(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask);
/**
* Get the enabled interrupts.
*
* @param hal Context of the HAL layer.
* @param out_int_mask Output of the enabled interrupts
*/
void sdio_slave_hal_hostint_get_ena(sdio_slave_context_t *hal, sdio_slave_hostint_t *out_int_mask);
/**
* Send general purpose interrupt (slave send to host).
* @param hal Context of the HAL layer.
* @param mask Interrupts to send, only `SDIO_SLAVE_HOSTINT_BIT*` are allowed.
*/
void sdio_slave_hal_hostint_send(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask);
/**
* Cleared the specified interrupts for the host.
*
* @param hal Context of the HAL layer.
* @param mask Interrupts to clear.
*/
void sdio_slave_hal_hostint_clear(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask);
/**
* Fetch the interrupt (host send to slave) status bits and clear all of them.
* @param hal Context of the HAL layer.
* @param out_int_mask Output interrupt status
*/
void sdio_slave_hal_slvint_fetch_clear(sdio_slave_context_t *hal, sdio_slave_ll_slvint_t *out_int_mask);
/**
* Get the value of a shared general purpose register.
*
* @param hal Context of the HAL layer.
* @param pos Position of the register, 4 bytes share a word. 0-63 except 24-27.
* @return The register value.
*/
uint8_t sdio_slave_hal_host_get_reg(sdio_slave_context_t *hal, int pos);
/**
* Set the value of shared general purpose register.
*
* @param hal Context of the HAL layer.
* @param pos Position of the register, 4 bytes share a word. 0-63 except 24-27.
* @param reg Value to set.
*/
void sdio_slave_hal_host_set_reg(sdio_slave_context_t *hal, int pos, uint8_t reg);

View File

@@ -0,0 +1,481 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32 SDIO slave register operations
// It's strange but `tx_*` regs for host->slave transfers while `rx_*` regs for slave->host transfers
// To reduce ambiguity, we call (host->slave, tx) transfers receiving and (slave->host, rx) transfers receiving
#pragma once
#include "hal/sdio_slave_hal.h"
#include "soc/slc_struct.h"
#include "soc/slc_reg.h"
#include "soc/host_struct.h"
#include "soc/host_reg.h"
#include "soc/hinf_struct.h"
#include "soc/lldesc.h"
/// Get address of the only SLC registers for ESP32
#define sdio_slave_ll_get_slc(ID) (&SLC)
/// Get address of the only HOST registers for ESP32
#define sdio_slave_ll_get_host(ID) (&HOST)
/// Get address of the only HINF registers for ESP32
#define sdio_slave_ll_get_hinf(ID) (&HINF)
/// Mask of general purpose interrupts sending from the host.
typedef enum {
SDIO_SLAVE_LL_SLVINT_0 = BIT(0), ///< General purpose interrupt bit 0.
SDIO_SLAVE_LL_SLVINT_1 = BIT(1),
SDIO_SLAVE_LL_SLVINT_2 = BIT(2),
SDIO_SLAVE_LL_SLVINT_3 = BIT(3),
SDIO_SLAVE_LL_SLVINT_4 = BIT(4),
SDIO_SLAVE_LL_SLVINT_5 = BIT(5),
SDIO_SLAVE_LL_SLVINT_6 = BIT(6),
SDIO_SLAVE_LL_SLVINT_7 = BIT(7),
} sdio_slave_ll_slvint_t;
/**
* Initialize the hardware.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_init(slc_dev_t *slc)
{
slc->slc0_int_ena.val = 0;
slc->conf0.slc0_rx_auto_wrback = 1;
slc->conf0.slc0_token_auto_clr = 0;
slc->conf0.slc0_rx_loop_test = 0;
slc->conf0.slc0_tx_loop_test = 0;
slc->conf1.slc0_rx_stitch_en = 0;
slc->conf1.slc0_tx_stitch_en = 0;
slc->conf1.slc0_len_auto_clr = 0;
slc->rx_dscr_conf.slc0_token_no_replace = 1;
}
/**
* Set the timing for the communication
*
* @param host Address of the host registers
* @param timing Timing configuration to set
*/
static inline void sdio_slave_ll_set_timing(host_dev_t *host, sdio_slave_timing_t timing)
{
switch(timing) {
case SDIO_SLAVE_TIMING_PSEND_PSAMPLE:
host->conf.frc_sdio20 = 0x1f;
host->conf.frc_sdio11 = 0;
host->conf.frc_pos_samp = 0x1f;
host->conf.frc_neg_samp = 0;
break;
case SDIO_SLAVE_TIMING_PSEND_NSAMPLE:
host->conf.frc_sdio20 = 0x1f;
host->conf.frc_sdio11 = 0;
host->conf.frc_pos_samp = 0;
host->conf.frc_neg_samp = 0x1f;
break;
case SDIO_SLAVE_TIMING_NSEND_PSAMPLE:
host->conf.frc_sdio20 = 0;
host->conf.frc_sdio11 = 0x1f;
host->conf.frc_pos_samp = 0x1f;
host->conf.frc_neg_samp = 0;
break;
case SDIO_SLAVE_TIMING_NSEND_NSAMPLE:
host->conf.frc_sdio20 = 0;
host->conf.frc_sdio11 = 0x1f;
host->conf.frc_pos_samp = 0;
host->conf.frc_neg_samp = 0x1f;
break;
}
}
/**
* Set the HS supported bit to be read by the host.
*
* @param hinf Address of the hinf registers
* @param hs true if supported, otherwise false.
*/
static inline void sdio_slave_ll_enable_hs(hinf_dev_t *hinf, bool hs)
{
if (hs) {
hinf->cfg_data1.sdio_ver = 0x232;
hinf->cfg_data1.highspeed_enable = 1;
}
}
/**
* Set the IO Ready bit to be read by the host.
*
* @param hinf Address of the hinf registers
* @param ready true if ready, otherwise false.
*/
static inline void sdio_slave_ll_set_ioready(hinf_dev_t *hinf, bool ready)
{
hinf->cfg_data1.sdio_ioready1 = (ready ? 1 : 0); //set IO ready to 1 to stop host from using
}
/*---------------------------------------------------------------------------
* Send
*--------------------------------------------------------------------------*/
/**
* Reset the sending DMA.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_send_reset(slc_dev_t *slc)
{
//reset to flush previous packets
slc->conf0.slc0_rx_rst = 1;
slc->conf0.slc0_rx_rst = 0;
}
/**
* Start the sending DMA with the given descriptor.
*
* @param slc Address of the SLC registers
* @param desc Descriptor to send
*/
static inline void sdio_slave_ll_send_start(slc_dev_t *slc, const lldesc_t *desc)
{
slc->slc0_rx_link.addr = (uint32_t)desc;
slc->slc0_rx_link.start = 1;
}
/**
* Write the PKT_LEN register to be written by the host to a certain value.
*
* @param slc Address of the SLC registers
* @param len Length to write
*/
static inline void sdio_slave_ll_send_write_len(slc_dev_t *slc, uint32_t len)
{
slc->slc0_len_conf.val = FIELD_TO_VALUE2(SLC_SLC0_LEN_WDATA, len) | FIELD_TO_VALUE2(SLC_SLC0_LEN_WR, 1);
}
/**
* Read the value of PKT_LEN register. The register may keep the same until read
* by the host.
*
* @param host Address of the host registers
* @return The value of PKT_LEN register.
*/
static inline uint32_t sdio_slave_ll_send_read_len(host_dev_t *host)
{
return host->pkt_len.reg_slc0_len;
}
/**
* Enable the rx_done interrupt. (sending)
*
* @param slc Address of the SLC registers
* @param ena true if enable, otherwise false.
*/
static inline void sdio_slave_ll_send_part_done_intr_ena(slc_dev_t *slc, bool ena)
{
slc->slc0_int_ena.rx_done = (ena ? 1 : 0);
}
/**
* Clear the rx_done interrupt. (sending)
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_send_part_done_clear(slc_dev_t *slc)
{
slc->slc0_int_clr.rx_done = 1;
}
/**
* Check whether the hardware is ready for the SW to use rx_done to invoke
* the ISR.
*
* @param slc Address of the SLC registers
* @return true if ready, otherwise false.
*/
static inline bool sdio_slave_ll_send_invoker_ready(slc_dev_t *slc)
{
return slc->slc0_int_raw.rx_done;
}
/**
* Stop the sending DMA.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_send_stop(slc_dev_t *slc)
{
slc->slc0_rx_link.stop = 1;
}
/**
* Enable the sending interrupt (rx_eof).
*
* @param slc Address of the SLC registers
* @param ena true to enable, false to disable
*/
static inline void sdio_slave_ll_send_intr_ena(slc_dev_t *slc, bool ena)
{
slc->slc0_int_ena.rx_eof = (ena? 1: 0);
}
/**
* Clear the sending interrupt (rx_eof).
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_send_intr_clr(slc_dev_t *slc)
{
slc->slc0_int_clr.rx_eof = 1;
}
/**
* Check whether the sending is done.
*
* @param slc Address of the SLC registers
* @return true if done, otherwise false
*/
static inline bool sdio_slave_ll_send_done(slc_dev_t *slc)
{
return slc->slc0_int_st.rx_eof != 0;
}
/**
* Clear the host interrupt indicating the slave having packet to be read.
*
* @param host Address of the host registers
*/
static inline void sdio_slave_ll_send_hostint_clr(host_dev_t *host)
{
host->slc0_int_clr.rx_new_packet = 1;
}
/*---------------------------------------------------------------------------
* Receive
*--------------------------------------------------------------------------*/
/**
* Enable the receiving interrupt.
*
* @param slc Address of the SLC registers
* @param ena
*/
static inline void sdio_slave_ll_recv_intr_ena(slc_dev_t *slc, bool ena)
{
slc->slc0_int_ena.tx_done = (ena ? 1 : 0);
}
/**
* Start receiving DMA with the given descriptor.
*
* @param slc Address of the SLC registers
* @param desc Descriptor of the receiving buffer.
*/
static inline void sdio_slave_ll_recv_start(slc_dev_t *slc, lldesc_t *desc)
{
slc->slc0_tx_link.addr = (uint32_t)desc;
slc->slc0_tx_link.start = 1;
}
/**
* Increase the receiving buffer counter by 1.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_size_inc(slc_dev_t *slc)
{
// fields wdata and inc_more should be written by the same instruction.
slc->slc0_token1.val = FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WDATA, 1) | FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_INC_MORE, 1);
}
/**
* Reset the receiving buffer.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_size_reset(slc_dev_t *slc)
{
slc->slc0_token1.val = FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WDATA, 0) | FIELD_TO_VALUE2(SLC_SLC0_TOKEN1_WR, 1);
}
/**
* Check whether there is a receiving finished event.
*
* @param slc Address of the SLC registers
* @return
*/
static inline bool sdio_slave_ll_recv_done(slc_dev_t *slc)
{
return slc->slc0_int_raw.tx_done != 0;
}
/**
* Clear the receiving finished interrupt.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_done_clear(slc_dev_t *slc)
{
slc->slc0_int_clr.tx_done = 1;
}
/**
* Restart the DMA. Call after you modified the next pointer of the tail descriptor to the appended
* descriptor.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_restart(slc_dev_t *slc)
{
slc->slc0_tx_link.restart = 1;
}
/**
* Reset the receiving DMA.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_reset(slc_dev_t *slc)
{
slc->conf0.slc0_tx_rst = 1;
slc->conf0.slc0_tx_rst = 0;
}
/**
* Stop the receiving DMA.
*
* @param slc Address of the SLC registers
*/
static inline void sdio_slave_ll_recv_stop(slc_dev_t *slc)
{
slc->slc0_tx_link.stop = 1;
}
/*---------------------------------------------------------------------------
* Host
*--------------------------------------------------------------------------*/
/**
* Get the address of the shared general purpose register. Internal.
*
* @param host Address of the host registers
* @param pos Position of the register, 0-63 except 24-27.
* @return address of the register.
*/
static inline intptr_t sdio_slave_ll_host_get_w_reg(host_dev_t* host, int pos)
{
return (intptr_t )&(host->conf_w0) + pos + (pos>23?4:0) + (pos>31?12:0);
}
/**
* Get the value of the shared general purpose register.
*
* @param host Address of the host registers
* @param pos Position of the register, 0-63, except 24-27.
* @return value of the register.
*/
static inline uint8_t sdio_slave_ll_host_get_reg(host_dev_t *host, int pos)
{
return *(uint8_t*)sdio_slave_ll_host_get_w_reg(host, pos);
}
/**
* Set the value of the shared general purpose register.
*
* @param host Address of the host registers
* @param pos Position of the register, 0-63, except 24-27.
* @param reg Value to set.
*/
static inline void sdio_slave_ll_host_set_reg(host_dev_t* host, int pos, uint8_t reg)
{
uint32_t* addr = (uint32_t*)(sdio_slave_ll_host_get_w_reg(host, pos) & (~3));
uint32_t shift = (pos % 4) * 8;
*addr &= ~(0xff << shift);
*addr |= ((uint32_t)reg << shift);
}
/**
* Get the interrupt enable bits for the host.
*
* @param host Address of the host registers
* @return Enabled interrupts
*/
static inline sdio_slave_hostint_t sdio_slave_ll_host_get_intena(host_dev_t* host)
{
return host->slc0_func1_int_ena.val;
}
/**
* Set the interrupt enable bits for the host.
*
* @param host Address of the host registers
* @param mask Mask of interrupts to enable
*/
static inline void sdio_slave_ll_host_set_intena(host_dev_t *host, const sdio_slave_hostint_t *mask)
{
host->slc0_func1_int_ena.val = (*mask);
}
/**
* Clear the interrupt bits for the host.
* @param host Address of the host registers
* @param mask Mask of interrupts to clear.
*/
static inline void sdio_slave_ll_host_intr_clear(host_dev_t* host, const sdio_slave_hostint_t *mask)
{
host->slc0_int_clr.val = (*mask);
}
/**
* Send general purpose interrupts to the host.
* @param slc Address of the SLC registers
* @param mask Mask of interrupts to seend to host
*/
static inline void sdio_slave_ll_host_send_int(slc_dev_t *slc, const sdio_slave_hostint_t *mask)
{
//use registers in SLC to trigger, rather than write HOST registers directly
//other interrupts than tohost interrupts are not supported yet
slc->intvec_tohost.slc0_intvec = (*mask);
}
/**
* Enable some of the slave interrups (send from host)
*
* @param slc Address of the SLC registers
* @param mask Mask of interrupts to enable, all those set to 0 will be disabled.
*/
static inline void sdio_slave_ll_slvint_set_ena(slc_dev_t *slc, const sdio_slave_ll_slvint_t *mask)
{
//other interrupts are not enabled
slc->slc0_int_ena.val = (slc->slc0_int_ena.val & (~0xff)) | ((*mask) & 0xff);
}
/**
* Fetch the slave interrupts (send from host) and clear them.
*
* @param slc Address of the SLC registers
* @param out_slv_int Output of the slave interrupts fetched and cleared.
*/
static inline void sdio_slave_ll_slvint_fetch_clear(slc_dev_t *slc, sdio_slave_ll_slvint_t *out_slv_int)
{
sdio_slave_ll_slvint_t slv_int = slc->slc0_int_st.val & 0xff;
*out_slv_int = slv_int;
slc->slc0_int_clr.val = slv_int;
}

View File

@@ -0,0 +1,47 @@
// 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.
#pragma once
#include "soc/soc.h"
/// Mask of interrupts sending to the host.
typedef enum {
SDIO_SLAVE_HOSTINT_BIT0 = BIT(0), ///< General purpose interrupt bit 0.
SDIO_SLAVE_HOSTINT_BIT1 = BIT(1),
SDIO_SLAVE_HOSTINT_BIT2 = BIT(2),
SDIO_SLAVE_HOSTINT_BIT3 = BIT(3),
SDIO_SLAVE_HOSTINT_BIT4 = BIT(4),
SDIO_SLAVE_HOSTINT_BIT5 = BIT(5),
SDIO_SLAVE_HOSTINT_BIT6 = BIT(6),
SDIO_SLAVE_HOSTINT_BIT7 = BIT(7),
SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET = BIT(23), ///< New packet available
} sdio_slave_hostint_t;
/// Timing of SDIO slave
typedef enum {
SDIO_SLAVE_TIMING_PSEND_PSAMPLE = 0,/**< Send at posedge, and sample at posedge. Default value for HS mode.
* Normally there's no problem using this to work in DS mode.
*/
SDIO_SLAVE_TIMING_NSEND_PSAMPLE ,///< Send at negedge, and sample at posedge. Default value for DS mode and below.
SDIO_SLAVE_TIMING_PSEND_NSAMPLE, ///< Send at posedge, and sample at negedge
SDIO_SLAVE_TIMING_NSEND_NSAMPLE, ///< Send at negedge, and sample at negedge
} sdio_slave_timing_t;
/// Configuration of SDIO slave mode
typedef enum {
SDIO_SLAVE_SEND_STREAM = 0, ///< Stream mode, all packets to send will be combined as one if possible
SDIO_SLAVE_SEND_PACKET = 1, ///< Packet mode, one packets will be sent one after another (only increase packet_len if last packet sent).
} sdio_slave_sending_mode_t;

View File

@@ -0,0 +1,90 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/lldesc.h"
#include "hal/sha_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Hashes a single message block
*
* @param sha_type SHA algorithm to hash with
* @param data_block Input message to be hashed
* @param block_word_len Length of the input message
* @param first_block Is this the first block in a message or a continuation?
*/
void sha_hal_hash_block(esp_sha_type sha_type, const void *data_block, size_t block_word_len, bool first_block);
/**
* @brief Polls and waits until the SHA engine is idle
*
*/
void sha_hal_wait_idle(void);
/**
* @brief Reads the current message digest from the SHA engine
*
* @param sha_type SHA algorithm used
* @param digest_state Output buffer to which to read message digest to
*/
void sha_hal_read_digest(esp_sha_type sha_type, void *digest_state);
#if SOC_SHA_SUPPORT_RESUME
/**
* @brief Writes the message digest to the SHA engine
*
* @param sha_type The SHA algorithm type
* @param digest_state Message digest to be written to SHA engine
*/
void sha_hal_write_digest(esp_sha_type sha_type, void *digest_state);
#endif
#if SOC_SHA_SUPPORT_DMA
/**
* @brief Hashes a number of message blocks using DMA
*
* @param sha_type SHA algorithm to hash with
* @param num_blocks Number of blocks to hash
* @param first_block Is this the first block in a message or a continuation?
*/
void sha_hal_hash_dma(esp_sha_type sha_type, size_t num_blocks, bool first_block);
#endif
#if SOC_SHA_SUPPORT_SHA512_T
/**
* @brief Calculates and sets the initial digiest for SHA512_t
*
* @param t_string
* @param t_len
*/
void sha_hal_sha512_init_hash(uint32_t t_string, uint8_t t_len);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,45 @@
// 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.
#pragma once
#include "sdkconfig.h"
/* Use enum from rom for backwards compatibility */
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/sha.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/sha.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/sha.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/sha.h"
#elif CONFIG_IDF_TARGET_ESP32H2
#include "esp32h2/rom/sha.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Use enum from rom for backwards compatibility */
#if CONFIG_IDF_TARGET_ESP32
typedef enum SHA_TYPE esp_sha_type;
#else
typedef SHA_TYPE esp_sha_type;
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,71 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SIGMADELTA.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/sigmadelta_periph.h"
#include "hal/sigmadelta_types.h"
#include "hal/sigmadelta_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
gpio_sd_dev_t *dev;
} sigmadelta_hal_context_t;
/**
* @brief Set Sigma-delta channel duty.
*
* @param hal Context of the HAL layer
* @param channel Sigma-delta channel number
* @param duty Sigma-delta duty of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90.
* The waveform is more like a random one in this range.
*/
#define sigmadelta_hal_set_duty(hal, channel, duty) sigmadelta_ll_set_duty((hal)->dev, channel, duty)
/**
* @brief Set Sigma-delta channel's clock pre-scale value.
*
* @param hal Context of the HAL layer
* @param channel Sigma-delta channel number
* @param prescale The divider of source clock, ranges from 0 to 255
*/
#define sigmadelta_hal_set_prescale(hal, channel, prescale) sigmadelta_ll_set_prescale((hal)->dev, channel, prescale)
/**
* @brief Init the SIGMADELTA hal and set the SIGMADELTA to the default configuration. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param sigmadelta_num The uart port number, the max port number is (SIGMADELTA_NUM_MAX -1)
*/
void sigmadelta_hal_init(sigmadelta_hal_context_t *hal, int sigmadelta_num);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,62 @@
// 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.
#pragma once
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SIGMADELTA port number, the max port number is (SIGMADELTA_NUM_MAX -1).
*/
typedef enum {
SIGMADELTA_PORT_0, /*!< SIGMADELTA port 0 */
SIGMADELTA_PORT_MAX, /*!< SIGMADELTA port max */
} sigmadelta_port_t;
_Static_assert(SIGMADELTA_PORT_MAX == SOC_SIGMADELTA_NUM, "Sigma-delta port num incorrect.");
/**
* @brief Sigma-delta channel list
*/
typedef enum {
SIGMADELTA_CHANNEL_0, /*!< Sigma-delta channel 0 */
SIGMADELTA_CHANNEL_1, /*!< Sigma-delta channel 1 */
SIGMADELTA_CHANNEL_2, /*!< Sigma-delta channel 2 */
SIGMADELTA_CHANNEL_3, /*!< Sigma-delta channel 3 */
#if SOC_SIGMADELTA_CHANNEL_NUM > 4
SIGMADELTA_CHANNEL_4, /*!< Sigma-delta channel 4 */
SIGMADELTA_CHANNEL_5, /*!< Sigma-delta channel 5 */
SIGMADELTA_CHANNEL_6, /*!< Sigma-delta channel 6 */
SIGMADELTA_CHANNEL_7, /*!< Sigma-delta channel 7 */
#endif
SIGMADELTA_CHANNEL_MAX, /*!< Sigma-delta channel max */
} sigmadelta_channel_t;
/**
* @brief Sigma-delta configure struct
*/
typedef struct {
sigmadelta_channel_t channel; /*!< Sigma-delta channel number */
int8_t sigmadelta_duty; /*!< Sigma-delta duty, duty ranges from -128 to 127. */
uint8_t sigmadelta_prescale; /*!< Sigma-delta prescale, prescale ranges from 0 to 255. */
uint8_t sigmadelta_gpio; /*!< Sigma-delta output io number, refer to gpio.h for more details. */
} sigmadelta_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,75 @@
// 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.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/cpu_hal.h"
#include "hal/soc_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_CPU_CORES_NUM > 1
// Utility functions for multicore targets
#define __SOC_HAL_PERFORM_ON_OTHER_CORES(action) { \
for (uint32_t i = 0, cur = cpu_hal_get_core_id(); i < SOC_CPU_CORES_NUM; i++) { \
if (i != cur) { \
action(i); \
} \
} \
}
#define SOC_HAL_STALL_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_stall_core);
#define SOC_HAL_UNSTALL_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_unstall_core);
#define SOC_HAL_RESET_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_reset_core);
/**
* Stall the specified CPU core.
*
* @note Has no effect if the core is already stalled - does not return an
* ESP_ERR_INVALID_STATE.
*
* @param core core to stall [0..SOC_CPU_CORES_NUM - 1]
*/
void soc_hal_stall_core(int core);
/**
* Unstall the specified CPU core.
*
* @note Has no effect if the core is already unstalled - does not return an
* ESP_ERR_INVALID_STATE.
*
* @param core core to unstall [0..SOC_CPU_CORES_NUM - 1]
*/
void soc_hal_unstall_core(int core);
#endif // SOC_CPU_CORES_NUM > 1
/**
* Reset the specified core.
*
* @param core core to reset [0..SOC_CPU_CORES_NUM - 1]
*/
#define soc_hal_reset_core(core) soc_ll_reset_core((core))
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,62 @@
// Copyright 2021 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.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI Flash Encryption
#include "hal/spi_flash_encrypted_ll.h"
/**
* @brief Enable the flash encryption
*/
void spi_flash_encryption_hal_enable(void);
/**
* @brief Disable the flash encryption
*/
void spi_flash_encryption_hal_disable(void);
/**
* Prepare flash encryption before operation.
*
* @param address The destination address in flash for the write operation.
* @param buffer Data for programming
* @param size Size to program.
*
* @note address and buffer must be 8-word aligned.
*/
void spi_flash_encryption_hal_prepare(uint32_t address, const uint32_t* buffer, uint32_t size);
/**
* @brief flash data encryption operation is done.
*/
void spi_flash_encryption_hal_done(void);
/**
* Destroy encrypted result
*/
void spi_flash_encryption_hal_destroy(void);
/**
* Check if is qualified to encrypt the buffer
*
* @param address the address of written flash partition.
* @param length Buffer size.
*/
bool spi_flash_encryption_hal_check(uint32_t address, uint32_t length);

View File

@@ -0,0 +1,280 @@
// Copyright 2010-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.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI Flash (common part)
#pragma once
#include "hal/spi_flash_ll.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#include "soc/soc_memory_types.h"
/* Hardware host-specific constants */
#define SPI_FLASH_HAL_MAX_WRITE_BYTES 64
#define SPI_FLASH_HAL_MAX_READ_BYTES 64
/**
* Generic driver context structure for all chips using the SPI peripheral.
* Include this into the HEAD of the driver data for other driver
* implementations that also use the SPI peripheral.
*/
typedef struct {
spi_flash_host_inst_t inst; ///< Host instance, containing host data and function pointer table. May update with the host (hardware version).
spi_dev_t *spi; ///< Pointer to SPI peripheral registers (SP1, SPI2 or SPI3). Set before initialisation.
int cs_num; ///< Which cs pin is used, 0-2.
struct {
uint8_t extra_dummy; ///< Pre-calculated extra dummy used for compensation
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock.
uint8_t cs_hold; ///< CS hold time config used by the host
uint8_t reserved2; ///< Reserved, set to 0.
};
spi_flash_ll_clock_reg_t clock_conf; ///< Pre-calculated clock configuration value
esp_flash_io_mode_t base_io_mode; ///< Default IO mode mask for common commands
uint32_t flags; ///< Flags for configurations with one set of driver code. (e.g. QPI mode, auto-suspend mode, 64-bit address mode, etc.)
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_SUSPEND BIT(0) ///< When the auto-suspend is setup in configuration.
#define SPI_FLASH_HOST_CONTEXT_FLAG_AUTO_RESUME BIT(1) ///< Setup auto-resume feature.
#define SPI_FLASH_HOST_CONTEXT_FLAG_OCTAL_MODE BIT(2) ///< Flash works under octal spi mode.
spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information.
uint32_t slicer_flags; /// Slicer flags for configuring how to slice data correctly while reading or writing.
#define SPI_FLASH_HOST_CONTEXT_SLICER_FLAG_DTR BIT(0) ///< Slice data according to DTR mode, the address and length must be even (A0=0).
} spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 40, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// This struct provide MSPI Flash necessary timing related config, should be consistent with that in union in `spi_flash_hal_config_t`.
typedef struct {
uint32_t extra_dummy;
uint32_t cs_hold;
uint8_t cs_setup;
spi_flash_ll_clock_reg_t clock_config;
} spi_flash_hal_timing_config_t;
/// Configuration structure for the SPI driver.
typedef struct {
union {
struct {
uint32_t extra_dummy; ///< extra dummy for timing compensation.
uint32_t cs_hold; ///< CS hold time config used by the host
uint8_t cs_setup; ///< (cycles-1) of prepare phase by spi clock
spi_flash_ll_clock_reg_t clock_config; ///< (optional) Clock configuration for Octal flash.
};
spi_flash_hal_timing_config_t timing_reg; ///< Reconfigure timing tuning regs.
};
bool iomux; ///< Whether the IOMUX is used, used for timing compensation.
int input_delay_ns; ///< Input delay on the MISO pin after the launch clock, used for timing compensation.
esp_flash_speed_t speed;///< SPI flash clock speed to work at.
spi_host_device_t host_id; ///< SPI peripheral ID.
int cs_num; ///< Which cs pin is used, 0-(SOC_SPI_PERIPH_CS_NUM-1).
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
bool octal_mode_en; ///< Octal spi flash mode enable bit 1: enable, 0: disable.
bool using_timing_tuning; ///< System exist SPI0/1 timing tuning, using value from system directely if set to 1.
esp_flash_io_mode_t default_io_mode; ///< Default flash io mode.
} spi_flash_hal_config_t;
/**
* Configure SPI flash hal settings.
*
* @param data Buffer to hold configured data, the buffer should be in DRAM to be available when cache disabled
* @param cfg Configurations to set
*
* @return
* - ESP_OK: success
* - ESP_ERR_INVALID_ARG: the data buffer is not in the DRAM.
*/
esp_err_t spi_flash_hal_init(spi_flash_hal_context_t *data_out, const spi_flash_hal_config_t *cfg);
/**
* Configure the device-related register before transactions.
*
* @param host The driver context.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_device_config(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
*
* @note This is usually used when the memspi interface doesn't support some
* particular commands. Since this function supports timing compensation, it is
* also used to receive some data when the frequency is high.
*
* @param host The driver context.
* @param trans The transaction to send, also holds the received data.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_common_command(spi_flash_host_inst_t *host, spi_flash_trans_t *trans);
/**
* Erase whole flash chip by using the erase chip (C7h) command.
*
* @param host The driver context.
*/
void spi_flash_hal_erase_chip(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address through the sector erase (20h)
* command. For 24bit address only.
*
* @param host The driver context.
* @param start_address Start address of the sector to erase.
*/
void spi_flash_hal_erase_sector(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific 64KB block by its start address through the 64KB block
* erase (D8h) command. For 24bit address only.
*
* @param host The driver context.
* @param start_address Start address of the block to erase.
*/
void spi_flash_hal_erase_block(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Program a page of the flash using the page program (02h) command. For 24bit address only.
*
* @param host The driver context.
* @param address Address of the page to program
* @param buffer Data to program
* @param length Size of the buffer in bytes, no larger than ``SPI_FLASH_HAL_MAX_WRITE_BYTES`` (64) bytes.
*/
void spi_flash_hal_program_page(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/**
* Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to
* configure the read command before calling this function.
*
* @param host The driver context.
* @param buffer Buffer to store the read data
* @param address Address to read
* @param length Length to read, no larger than ``SPI_FLASH_HAL_MAX_READ_BYTES`` (64) bytes.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_read(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/**
* @brief Send the write enable (06h) or write disable (04h) command to the flash chip.
*
* @param driver The driver context.
* @param wp true to enable the write protection, otherwise false.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_set_write_protect(spi_flash_host_inst_t *host, bool wp);
/**
* Check whether the SPI host is idle and can perform other operations.
*
* @param host The driver context.
*
* @return 0:busy, 1:idle, 2:suspended.
*/
uint32_t spi_flash_hal_check_status(spi_flash_host_inst_t *host);
/**
* @brief Configure the SPI host hardware registers for the specified io mode.
*
* Note that calling this configures SPI host registers, so if running any
* other commands as part of set_io_mode() then these must be run before
* calling this function.
*
* The command value, address length and dummy cycles are configured according
* to the format of read commands:
*
* - command: 8 bits, value set.
* - address: 24 bits
* - dummy: cycles to compensate the input delay
* - out & in data: 0 bits.
*
* The following commands still need to:
*
* - Read data: set address value and data (length and contents), no need
* to touch command and dummy phases.
* - Common read: set command value, address value (or length to 0 if not used)
* - Common write: set command value, address value (or length to 0 if not
* used), disable dummy phase, and set output data.
*
* @param host The driver context
* @param io_mode The HW read mode to use
* @param addr_bitlen Length of the address phase, in bits
* @param dummy_cyclelen_base Base cycles of the dummy phase, some extra dummy cycles may be appended to compensate the timing.
* @param command Actual reading command to send to flash chip on the bus.
*
* @return always return ESP_OK.
*/
esp_err_t spi_flash_hal_configure_host_io_mode(spi_flash_host_inst_t *host, uint32_t command, uint32_t addr_bitlen,
int dummy_cyclelen_base, esp_flash_io_mode_t io_mode);
/**
* Poll until the last operation is done.
*
* @param host The driver context.
*/
void spi_flash_hal_poll_cmd_done(spi_flash_host_inst_t *host);
/**
* Check whether the given buffer can be used as the write buffer directly. If 'chip' is connected to the main SPI bus, we can only write directly from
* regions that are accessible ith cache disabled. *
*
* @param host The driver context
* @param p The buffer holding data to send.
*
* @return True if the buffer can be used to send data, otherwise false.
*/
bool spi_flash_hal_supports_direct_write(spi_flash_host_inst_t *host, const void *p);
/**
* Check whether the given buffer can be used as the read buffer directly. If 'chip' is connected to the main SPI bus, we can only read directly from
* regions that are accessible ith cache disabled. *
*
* @param host The driver context
* @param p The buffer to hold the received data.
*
* @return True if the buffer can be used to receive data, otherwise false.
*/
bool spi_flash_hal_supports_direct_read(spi_flash_host_inst_t *host, const void *p);
/**
* @brief Resume flash chip status from suspend.
*
* @param host The driver context.
*
*/
void spi_flash_hal_resume(spi_flash_host_inst_t *host);
/**
* @brief Set the flash into suspend status manually.
*
* @param host The driver context.
*
*/
void spi_flash_hal_suspend(spi_flash_host_inst_t *host);
/**
* To setup for reading flash suspend status register
*
* @param host The driver context.
* @param sus_conf Flash chip suspend feature configuration, mainly for command config, may vary from chip to chip.
*
* @return Always ESP_OK
*/
esp_err_t spi_flash_hal_setup_read_suspend(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);

View File

@@ -0,0 +1,257 @@
// Copyright 2010-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.
#pragma once
#include <esp_types.h>
#include <esp_bit_defs.h>
#include "esp_flash_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Definition of a common transaction. Also holds the return value. */
typedef struct {
uint8_t reserved; ///< Reserved, must be 0.
uint8_t mosi_len; ///< Output data length, in bytes
uint8_t miso_len; ///< Input data length, in bytes
uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address
uint32_t address; ///< Address to perform operation on
const uint8_t *mosi_data; ///< Output data to salve
uint8_t *miso_data; ///< [out] Input data from slave, little endian
uint32_t flags; ///< Flags for this transaction. Set to 0 for now.
#define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits
#define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use
uint32_t io_mode; ///< Flash working mode when `SPI_FLASH_IGNORE_BASEIO` is specified.
} spi_flash_trans_t;
/**
* @brief SPI flash clock speed values, always refer to them by the enum rather
* than the actual value (more speed may be appended into the list).
*
* A strategy to select the maximum allowed speed is to enumerate from the
* ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and
* decrease the speed until the probing success.
*/
typedef enum {
ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz
ESP_FLASH_10MHZ, ///< The flash runs under 10MHz
ESP_FLASH_20MHZ, ///< The flash runs under 20MHz
ESP_FLASH_26MHZ, ///< The flash runs under 26MHz
ESP_FLASH_40MHZ, ///< The flash runs under 40MHz
ESP_FLASH_80MHZ, ///< The flash runs under 80MHz
ESP_FLASH_120MHZ, ///< The flash runs under 120MHz, 120MHZ can only be used by main flash after timing tuning in system. Do not use this directely in any API.
ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``.
} esp_flash_speed_t;
///Lowest speed supported by the driver, currently 5 MHz
#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ
// These bits are not quite like "IO mode", but are able to be appended into the io mode and used by the HAL.
#define SPI_FLASH_CONFIG_CONF_BITS BIT(31) ///< OR the io_mode with this mask, to enable the dummy output feature or replace the first several dummy bits into address to meet the requirements of conf bits. (Used in DIO/QIO/OIO mode)
/** @brief Mode used for reading from SPI flash */
typedef enum {
SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed
SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed
SPI_FLASH_DOUT, ///< Data read using dual I/O
SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O
SPI_FLASH_QOUT, ///< Data read using quad I/O
SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O
#define SPI_FLASH_OPI_FLAG 16 ///< A flag for flash work in opi mode, the io mode below are opi, above are SPI/QSPI mode. DO NOT use this value in any API.
SPI_FLASH_OPI_STR = SPI_FLASH_OPI_FLAG,///< Only support on OPI flash, flash read and write under STR mode
SPI_FLASH_OPI_DTR,///< Only support on OPI flash, flash read and write under DTR mode
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_io_mode_t;
/// Configuration structure for the flash chip suspend feature.
typedef struct {
uint32_t sus_mask; ///< SUS/SUS1/SUS2 bit in flash register.
struct {
uint32_t cmd_rdsr :8; ///< Read flash status register(2) command.
uint32_t sus_cmd :8; ///< Flash suspend command.
uint32_t res_cmd :8; ///< Flash resume command.
uint32_t reserved :8; ///< Reserved, set to 0.
};
} spi_flash_sus_cmd_conf;
/// Structure for flash encryption operations.
typedef struct
{
/**
* @brief Enable the flash encryption
*/
void (*flash_encryption_enable)(void);
/**
* @brief Disable the flash encryption
*/
void (*flash_encryption_disable)(void);
/**
* Prepare flash encryption before operation.
*
* @param address The destination address in flash for the write operation.
* @param buffer Data for programming
* @param size Size to program.
*
* @note address and buffer must be 8-word aligned.
*/
void (*flash_encryption_data_prepare)(uint32_t address, const uint32_t* buffer, uint32_t size);
/**
* @brief flash data encryption operation is done.
*/
void (*flash_encryption_done)(void);
/**
* Destroy encrypted result
*/
void (*flash_encryption_destroy)(void);
/**
* Check if is qualified to encrypt the buffer
*
* @param address the address of written flash partition.
* @param length Buffer size.
*/
bool (*flash_encryption_check)(uint32_t address, uint32_t length);
} spi_flash_encryption_t;
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
struct spi_flash_host_driver_s;
typedef struct spi_flash_host_driver_s spi_flash_host_driver_t;
/** SPI Flash Host driver instance */
typedef struct {
const struct spi_flash_host_driver_s* driver; ///< Pointer to the implementation function table
// Implementations can wrap this structure into their own ones, and append other data here
} spi_flash_host_inst_t ;
/** Host driver configuration and context structure. */
struct spi_flash_host_driver_s {
/**
* Configure the device-related register before transactions. This saves
* some time to re-configure those registers when we send continuously
*/
esp_err_t (*dev_config)(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
*/
esp_err_t (*common_command)(spi_flash_host_inst_t *host, spi_flash_trans_t *t);
/**
* Read flash ID.
*/
esp_err_t (*read_id)(spi_flash_host_inst_t *host, uint32_t *id);
/**
* Erase whole flash chip.
*/
void (*erase_chip)(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address.
*/
void (*erase_sector)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific block by its start address.
*/
void (*erase_block)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Read the status of the flash chip.
*/
esp_err_t (*read_status)(spi_flash_host_inst_t *host, uint8_t *out_sr);
/**
* Disable write protection.
*/
esp_err_t (*set_write_protect)(spi_flash_host_inst_t *host, bool wp);
/**
* Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length.
*/
void (*program_page)(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/** Check whether given buffer can be directly used to write */
bool (*supports_direct_write)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for write data. The `program_page` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to write
* @param len Length request to write
* @param align_addr Output of the aligned address to write to
* @param page_size Physical page size of the flash chip
* @return Length that can be actually written in one `program_page` call
*/
int (*write_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr,
uint32_t page_size);
/**
* Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length.
*/
esp_err_t (*read)(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for read data. The `read` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to read
* @param len Length request to read
* @param align_addr Output of the aligned address to read
* @param page_size Physical page size of the flash chip
* @return Length that can be actually read in one `read` call
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check the host status, 0:busy, 1:idle, 2:suspended.
*/
uint32_t (*host_status)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
esp_err_t (*configure_host_io_mode)(spi_flash_host_inst_t *host, uint32_t command,
uint32_t addr_bitlen, int dummy_bitlen_base,
esp_flash_io_mode_t io_mode);
/**
* Internal use, poll the HW until the last operation is done.
*/
void (*poll_cmd_done)(spi_flash_host_inst_t *host);
/**
* For some host (SPI1), they are shared with a cache. When the data is
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
/**
* Suspend check erase/program operation, reserved for ESP32-C3 and ESP32-S3 spi flash ROM IMPL.
*/
void (*check_suspend)(spi_flash_host_inst_t *host);
/**
* Resume flash from suspend manually
*/
void (*resume)(spi_flash_host_inst_t *host);
/**
* Set flash in suspend status manually
*/
void (*suspend)(spi_flash_host_inst_t *host);
/**
* Suspend feature setup for setting cmd and status register mask.
*/
esp_err_t (*sus_setup)(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);
};
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,271 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI master (common part)
// SPI HAL usages:
// 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used
// 3. setup the clock speed (since this takes long time)
// 4. call setup_device to update parameters for the specific device
// 5. call setup_trans to update parameters for the specific transaction
// 6. prepare data to send, and prepare the receiving buffer
// 7. trigger user defined SPI transaction to start
// 8. wait until the user transaction is done
// 9. fetch the received data
// Parameter to be updated only during ``setup_device`` will be highlighted in the
// field comments.
#pragma once
#include "hal/spi_ll.h"
#include <esp_err.h>
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
/**
* Input parameters to the ``spi_hal_cal_clock_conf`` to calculate the timing configuration
*/
typedef struct {
uint32_t half_duplex; ///< Whether half duplex mode is used, device specific
uint32_t no_compensate; ///< No need to add dummy to compensate the timing, device specific
uint32_t clock_speed_hz; ///< Desired frequency.
uint32_t duty_cycle; ///< Desired duty cycle of SPI clock
uint32_t input_delay_ns; /**< Maximum delay between SPI launch clock and the data to be valid.
* This is used to compensate/calculate the maximum frequency allowed.
* Left 0 if not known.
*/
bool use_gpio; ///< True if the GPIO matrix is used, otherwise false
} spi_hal_timing_param_t;
/**
* Timing configuration structure that should be calculated by
* ``spi_hal_cal_clock_conf`` at initialization and hold. Filled into the
* ``timing_conf`` member of the context of HAL before setup a device.
*/
typedef struct {
spi_ll_clock_val_t clock_reg; ///< Register value used by the LL layer
int timing_dummy; ///< Extra dummy needed to compensate the timing
int timing_miso_delay; ///< Extra miso delay clocks to compensate the timing
} spi_hal_timing_conf_t;
/**
* DMA configuration structure
* Should be set by driver at initialization
*/
typedef struct {
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
} spi_hal_config_t;
/**
* Transaction configuration structure, this should be assigned by driver each time.
* All these parameters will be updated to the peripheral every transaction.
*/
typedef struct {
uint16_t cmd; ///< Command value to be sent
int cmd_bits; ///< Length (in bits) of the command phase
int addr_bits; ///< Length (in bits) of the address phase
int dummy_bits; ///< Base length (in bits) of the dummy phase. Note when the compensation is enabled, some extra dummy bits may be appended.
int tx_bitlen; ///< TX length, in bits
int rx_bitlen; ///< RX length, in bits
uint64_t addr; ///< Address value to be sent
uint8_t *send_buffer; ///< Data to be sent
uint8_t *rcv_buffer; ///< Buffer to hold the receive data.
spi_line_mode_t line_mode; ///< SPI line mode of this transaction
int cs_keep_active; ///< Keep CS active after transaction
} spi_hal_trans_config_t;
/**
* Context that should be maintained by both the driver and the HAL.
*/
typedef struct {
/* These two need to be malloced by the driver first */
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
/* Configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM (DMA -> RAM).
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral (RAM -> DMA).
bool dma_enabled; ///< Whether the DMA is enabled, do not update after initialization
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
/* Internal parameters, don't touch */
spi_hal_trans_config_t trans_config; ///< Transaction configuration
} spi_hal_context_t;
/**
* Device configuration structure, this should be initialised by driver based on different devices respectively.
* All these parameters will be updated to the peripheral only when ``spi_hal_setup_device``.
* They may not get updated when ``spi_hal_setup_trans``.
*/
typedef struct {
int mode; ///< SPI mode, device specific
int cs_setup; ///< Setup time of CS active edge before the first SPI clock, device specific
int cs_hold; ///< Hold time of CS inactive edge after the last SPI clock, device specific
int cs_pin_id; ///< CS pin to use, 0-2, otherwise all the CS pins are not used. Device specific
spi_hal_timing_conf_t timing_conf; /**< This structure holds the pre-calculated timing configuration for the device
* at initialization, device specific
*/
struct {
uint32_t sio : 1; ///< Whether to use SIO mode, device specific
uint32_t half_duplex : 1; ///< Whether half duplex mode is used, device specific
uint32_t tx_lsbfirst : 1; ///< Whether LSB is sent first for TX data, device specific
uint32_t rx_lsbfirst : 1; ///< Whether LSB is received first for RX data, device specific
uint32_t no_compensate : 1; ///< No need to add dummy to compensate the timing, device specific
#if SOC_SPI_SUPPORT_AS_CS
uint32_t as_cs : 1; ///< Whether to toggle the CS while the clock toggles, device specific
#endif
uint32_t positive_cs : 1; ///< Whether the postive CS feature is abled, device specific
};//boolean configurations
} spi_hal_dev_config_t;
/**
* Init the peripheral and the context.
*
* @param hal Context of the HAL layer.
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for SPI2 and 2 for SPI3.
* @param hal_config Configuration of the hal defined by the upper layer.
*/
void spi_hal_init(spi_hal_context_t *hal, uint32_t host_id, const spi_hal_config_t *hal_config);
/**
* Deinit the peripheral (and the context if needed).
*
* @param hal Context of the HAL layer.
*/
void spi_hal_deinit(spi_hal_context_t *hal);
/**
* Setup device-related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
*/
void spi_hal_setup_device(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev);
/**
* Setup transaction related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
* @param hal_trans Transaction configuration
*/
void spi_hal_setup_trans(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/**
* Prepare the data for the current transaction.
*
* @param hal Context of the HAL layer.
* @param hal_dev Device configuration
* @param hal_trans Transaction configuration
*/
void spi_hal_prepare_data(spi_hal_context_t *hal, const spi_hal_dev_config_t *hal_dev, const spi_hal_trans_config_t *hal_trans);
/**
* Trigger start a user-defined transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_hal_user_start(const spi_hal_context_t *hal);
/**
* Check whether the transaction is done (trans_done is set).
*
* @param hal Context of the HAL layer.
*/
bool spi_hal_usr_is_done(const spi_hal_context_t *hal);
/**
* Post transaction operations, mainly fetch data from the buffer.
*
* @param hal Context of the HAL layer.
*/
void spi_hal_fetch_result(const spi_hal_context_t *hal);
/*----------------------------------------------------------
* Utils
* ---------------------------------------------------------*/
/**
* Calculate the configuration of clock and timing. The configuration will be used when ``spi_hal_setup_device``.
*
* It is highly suggested to do this at initialization, since it takes long time.
*
* @param timing_param Input parameters to calculate timing configuration
* @param out_freq Output of the actual frequency, left NULL if not required.
* @param timing_conf Output of the timing configuration.
*
* @return ESP_OK if desired is available, otherwise fail.
*/
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, int *out_freq, spi_hal_timing_conf_t *timing_conf);
/**
* Get the frequency actual used.
*
* @param hal Context of the HAL layer.
* @param fapb APB clock frequency.
* @param hz Desired frequencyc.
* @param duty_cycle Desired duty cycle.
*/
int spi_hal_master_cal_clock(int fapb, int hz, int duty_cycle);
/**
* Get the timing configuration for given parameters.
*
* @param eff_clk Actual SPI clock frequency
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
* be valid. This is used to compensate/calculate the maximum frequency
* allowed. Left 0 if not known.
* @param dummy_n Dummy cycles required to correctly read the data.
* @param miso_delay_n suggested delay on the MISO line, in APB clocks.
*/
void spi_hal_cal_timing(int eff_clk, bool gpio_is_used, int input_delay_ns, int *dummy_n, int *miso_delay_n);
/**
* Get the maximum frequency allowed to read if no compensation is used.
*
* @param gpio_is_used true if the GPIO matrix is used, otherwise false.
* @param input_delay_ns Maximum delay between SPI launch clock and the data to
* be valid. This is used to compensate/calculate the maximum frequency
* allowed. Left 0 if not known.
*/
int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);

View File

@@ -0,0 +1,163 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI slave (common part)
// SPI slave HAL usages:
// 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used
// 3. call setup_device to update parameters for the device
// 4. prepare data to send, and prepare the receiving buffer
// 5. trigger user defined SPI transaction to start
// 6. wait until the user transaction is done
// 7. store the received data and get the length
// 8. check and reset the DMA (if needed) before the next transaction
#pragma once
#include <esp_types.h>
#include "soc/lldesc.h"
#include "soc/spi_struct.h"
#include "soc/soc_caps.h"
#include "hal/spi_ll.h"
/**
* Context that should be maintained by both the driver and the HAL.
*/
typedef struct {
/* configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
/* should be configured by driver at initialization */
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
/*
* configurations to be filled after ``spi_slave_hal_init``. Updated to
* peripheral registers when ``spi_slave_hal_setup_device`` is called.
*/
struct {
uint32_t rx_lsbfirst : 1;
uint32_t tx_lsbfirst : 1;
uint32_t use_dma : 1;
};
int mode;
/*
* Transaction specific (data), all these parameters will be updated to the
* peripheral every transaction.
*/
uint32_t bitlen; ///< Expected maximum length of the transaction, in bits.
const void *tx_buffer; ///< Data to be sent
void *rx_buffer; ///< Buffer to hold the received data.
/* Other transaction result after one transaction */
uint32_t rcv_bitlen; ///< Length of the last transaction, in bits.
} spi_slave_hal_context_t;
typedef struct {
uint32_t host_id; ///< SPI controller ID
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
} spi_slave_hal_config_t;
/**
* Init the peripheral and the context.
*
* @param hal Context of the HAL layer.
* @param hal_config Configuration of the HAL
*/
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config);
/**
* Deinit the peripheral (and the context if needed).
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_deinit(spi_slave_hal_context_t *hal);
/**
* Setup device-related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal);
/**
* Prepare the data for the current transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal);
/**
* Trigger start a user-defined transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal);
/**
* Check whether the transaction is done (trans_done is set).
*
* @param hal Context of the HAL layer.
*/
bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal);
/**
* Post transaction operations, fetch data from the buffer and recored the length.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_store_result(spi_slave_hal_context_t *hal);
/**
* Get the length of last transaction, in bits. Should be called after ``spi_slave_hal_store_result``.
*
* Note that if last transaction is longer than configured before, the return
* value will be truncated to the configured length.
*
* @param hal Context of the HAL layer.
*
* @return Length of the last transaction, in bits.
*/
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
/**
* Check whether we need to reset the DMA according to the status of last transactions.
*
* In ESP32, sometimes we may need to reset the DMA for the slave before the
* next transaction. Call this to check it.
*
* @param hal Context of the HAL layer.
*
* @return true if reset is needed, else false.
*/
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal);

View File

@@ -0,0 +1,318 @@
// Copyright 2015-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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
/*
* The HAL layer for SPI Slave HD mode.
*
* Usage (segment mode):
* - Firstly, initialize the slave with `spi_slave_hd_hal_init`
*
* - Event handling:
* - (Optional) Call ``spi_slave_hd_hal_enable_event_intr`` to enable the used interrupts
* - (Basic) Call ``spi_slave_hd_hal_check_clear_event`` to check whether an event happen, and also
* clear its interrupt. For events: SPI_EV_BUF_TX, SPI_EV_BUF_RX, SPI_EV_BUF_RX, SPI_EV_CMD9,
* SPI_EV_CMDA.
* - (Advanced) Call ``spi_slave_hd_hal_check_disable_event`` to disable the interrupt of an event,
* so that the task can call ``spi_slave_hd_hal_invoke_event_intr`` later to manually invoke the
* ISR. For SPI_EV_SEND, SPI_EV_RECV.
*
* - TXDMA:
* - To send data through DMA, call `spi_slave_hd_hal_txdma`
* - When the operation is done, SPI_EV_SEND will be triggered.
*
* - RXDMA:
* - To receive data through DMA, call `spi_slave_hd_hal_rxdma`
* - When the operation is done, SPI_EV_RECV will be triggered.
* - Call ``spi_slave_hd_hal_rxdma_seg_get_len`` to get the received length
*
* - Shared buffer:
* - Call ``spi_slave_hd_hal_write_buffer`` to write the shared register buffer. When the buffer is
* read by the master (regardless of the read address), SPI_EV_BUF_TX will be triggered
* - Call ``spi_slave_hd_hal_read_buffer`` to read the shared register buffer. When the buffer is
* written by the master (regardless of the written address), SPI_EV_BUF_RX will be triggered.
*/
#pragma once
#include <esp_types.h>
#include "esp_err.h"
#include "hal/spi_ll.h"
#include "hal/spi_types.h"
/**
* @brief Type of dma descriptor with appended members
* this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users.
*/
typedef struct {
lldesc_t desc; ///< DMA descriptor
void *arg; ///< This points to the transaction descriptor user passed in
} spi_slave_hd_hal_desc_append_t;
/// Configuration of the HAL
typedef struct {
uint32_t host_id; ///< Host ID of the spi peripheral
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
bool dma_enabled; ///< DMA enabled or not
uint32_t tx_dma_chan; ///< TX DMA channel used.
uint32_t rx_dma_chan; ///< RX DMA channel used.
bool append_mode; ///< True for DMA append mode, false for segment mode
uint32_t spics_io_num; ///< CS GPIO pin for this device
uint8_t mode; ///< SPI mode (0-3)
uint32_t command_bits; ///< command field bits, multiples of 8 and at least 8.
uint32_t address_bits; ///< address field bits, multiples of 8 and at least 8.
uint32_t dummy_bits; ///< dummy field bits, multiples of 8 and at least 8.
struct {
uint32_t tx_lsbfirst : 1; ///< Whether TX data should be sent with LSB first.
uint32_t rx_lsbfirst : 1; ///< Whether RX data should be read with LSB first.
};
} spi_slave_hd_hal_config_t;
/// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`.
typedef struct {
/* These two need to be malloced by the driver first */
spi_slave_hd_hal_desc_append_t *dmadesc_tx; ///< Head of the TX DMA descriptors.
spi_slave_hd_hal_desc_append_t *dmadesc_rx; ///< Head of the RX DMA descriptors.
/* address of the hardware */
spi_dev_t *dev; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
bool dma_enabled; ///< DMA enabled or not
uint32_t tx_dma_chan; ///< TX DMA channel used.
uint32_t rx_dma_chan; ///< RX DMA channel used.
bool append_mode; ///< True for DMA append mode, false for segment mode
uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``.
spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t tx_dummy_head; ///< Dummy descriptor for ``tx_dma_head`` to start
uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup
uint32_t tx_recycled_desc_cnt; ///< Number of the TX descriptors that could be recycled
spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t rx_dummy_head; ///< Dummy descriptor for ``rx_dma_head`` to start
uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup
uint32_t rx_recycled_desc_cnt; ///< Number of the RX descriptors that could be recycled
/* Internal status used by the HAL implementation, initialized as 0. */
uint32_t intr_not_triggered;
bool tx_dma_started;
bool rx_dma_started;
} spi_slave_hd_hal_context_t;
/**
* @brief Initialize the hardware and part of the context
*
* @param hal Context of the HAL layer
* @param hal_config Configuration of the HAL
*/
void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_hal_config_t *hal_config);
/**
* @brief Get the size of one DMA descriptor
*
* @param hal Context of the HAL layer
* @param bus_size SPI bus maximum transfer size, in bytes.
* @return Total size needed for all the DMA descriptors
*/
uint32_t spi_slave_hd_hal_get_total_desc_size(spi_slave_hd_hal_context_t *hal, uint32_t bus_size);
/**
* @brief Get the actual bus size
*
* @param hal Context of the HAL layer
* @return Actual bus transaction size
*/
uint32_t spi_salve_hd_hal_get_max_bus_size(spi_slave_hd_hal_context_t *hal);
/**
* @brief Check and clear signal of one event
*
* @param hal Context of the HAL layer
* @param ev Event to check
* @return True if event triggered, otherwise false
*/
bool spi_slave_hd_hal_check_clear_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
/**
* @brief Check and clear the interrupt of one event.
*
* @note The event source will be kept, so that the interrupt can be invoked by
* :cpp:func:`spi_slave_hd_hal_invoke_event_intr`. If event not triggered, its interrupt source
* will not be disabled either.
*
* @param hal Context of the HAL layer
* @param ev Event to check and disable
* @return True if event triggered, otherwise false
*/
bool spi_slave_hd_hal_check_disable_event(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
/**
* @brief Enable to invole the ISR of corresponding event.
*
* @note The function, compared with :cpp:func:`spi_slave_hd_hal_enable_event_intr`, contains a
* workaround to force trigger the interrupt, even if the interrupt source cannot be initialized
* correctly.
*
* @param hal Context of the HAL layer
* @param ev Event (reason) to invoke the ISR
*/
void spi_slave_hd_hal_invoke_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
/**
* @brief Enable the interrupt source of corresponding event.
*
* @param hal Context of the HAL layer
* @param ev Event whose corresponding interrupt source should be enabled.
*/
void spi_slave_hd_hal_enable_event_intr(spi_slave_hd_hal_context_t* hal, spi_event_t ev);
////////////////////////////////////////////////////////////////////////////////
// RX DMA
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Start the RX DMA operation to the specified buffer.
*
* @param hal Context of the HAL layer
* @param[out] out_buf Buffer to receive the data
* @param len Maximul length to receive
*/
void spi_slave_hd_hal_rxdma(spi_slave_hd_hal_context_t *hal, uint8_t *out_buf, size_t len);
/**
* @brief Get the length of total received data
*
* @param hal Context of the HAL layer
* @return The received length
*/
int spi_slave_hd_hal_rxdma_seg_get_len(spi_slave_hd_hal_context_t *hal);
////////////////////////////////////////////////////////////////////////////////
// TX DMA
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Start the TX DMA operation with the specified buffer
*
* @param hal Context of the HAL layer
* @param data Buffer of data to send
* @param len Size of the buffer, also the maximum length to send
*/
void spi_slave_hd_hal_txdma(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len);
////////////////////////////////////////////////////////////////////////////////
// Shared buffer
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Read from the shared register buffer
*
* @param hal Context of the HAL layer
* @param addr Address of the shared regsiter to read
* @param out_data Buffer to store the read data
* @param len Length to read from the shared buffer
*/
void spi_slave_hd_hal_read_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *out_data, size_t len);
/**
* @brief Write the shared register buffer
*
* @param hal Context of the HAL layer
* @param addr Address of the shared register to write
* @param data Buffer of the data to write
* @param len Length to write into the shared buffer
*/
void spi_slave_hd_hal_write_buffer(spi_slave_hd_hal_context_t *hal, int addr, uint8_t *data, size_t len);
/**
* @brief Get the length of previous transaction.
*
* @param hal Context of the HAL layer
* @return The length of previous transaction
*/
int spi_slave_hd_hal_get_rxlen(spi_slave_hd_hal_context_t *hal);
/**
* @brief Get the address of last transaction
*
* @param hal Context of the HAL layer
* @return The address of last transaction
*/
int spi_slave_hd_hal_get_last_addr(spi_slave_hd_hal_context_t *hal);
#if CONFIG_IDF_TARGET_ESP32S2
//Append mode is only supported on ESP32S2 now
////////////////////////////////////////////////////////////////////////////////
// Append Mode
////////////////////////////////////////////////////////////////////////////////
/**
* @brief Return the finished TX transaction
*
* @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
* This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
* this API will go wrong.
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_tx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans);
/**
* @brief Return the finished RX transaction
*
* @note This API is based on this assumption: the hardware behaviour of current transaction completion is only modified by the its own caller layer.
* This means if some other code changed the hardware behaviour (e.g. clear intr raw bit), or the caller call this API without noticing the HW behaviour,
* this API will go wrong.
*
* @param hal Context of the HAL layer
* @param out_trans Pointer to the caller-defined transaction
* @param out_len Actual number of bytes of received data
* @return 1: Transaction is finished; 0: Transaction is not finished
*/
bool spi_slave_hd_hal_get_rx_finished_trans(spi_slave_hd_hal_context_t *hal, void **out_trans, size_t *out_len);
/**
* @brief Load the TX DMA descriptors without stopping the DMA
*
* @param hal Context of the HAL layer
* @param data Buffer of the transaction data
* @param len Length of the data
* @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_tx_finished_trans`` when transaction is finished
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state.
*/
esp_err_t spi_slave_hd_hal_txdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
/**
* @brief Load the RX DMA descriptors without stopping the DMA
*
* @param hal Context of the HAL layer
* @param data Buffer of the transaction data
* @param len Length of the data
* @param arg Pointer used by the caller to indicate the tranaction. Will be returned by ``spi_slave_hd_hal_get_rx_finished_trans`` when transaction is finished
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: Function called in invalid state.
*/
esp_err_t spi_slave_hd_hal_rxdma_append(spi_slave_hd_hal_context_t *hal, uint8_t *data, size_t len, void *arg);
#endif //#if CONFIG_IDF_TARGET_ESP32S2

View File

@@ -0,0 +1,89 @@
// 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.
#pragma once
#include <stdint.h>
#include "esp_attr.h"
#include "esp_bit_defs.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
/**
* @brief Enum with the three SPI peripherals that are software-accessible in it
*/
typedef enum {
//SPI1 can be used as GPSPI only on ESP32
SPI1_HOST=0, ///< SPI1
SPI2_HOST=1, ///< SPI2
SPI3_HOST=2, ///< SPI3
} spi_host_device_t;
/// SPI Events
typedef enum {
/* Slave HD Only */
SPI_EV_BUF_TX = BIT(0), ///< The buffer has sent data to master.
SPI_EV_BUF_RX = BIT(1), ///< The buffer has received data from master.
SPI_EV_SEND_DMA_READY = BIT(2), ///< Slave has loaded its TX data buffer to the hardware (DMA).
SPI_EV_SEND = BIT(3), ///< Master has received certain number of the data, the number is determined by Master.
SPI_EV_RECV_DMA_READY = BIT(4), ///< Slave has loaded its RX data buffer to the hardware (DMA).
SPI_EV_RECV = BIT(5), ///< Slave has received certain number of data from master, the number is determined by Master.
SPI_EV_CMD9 = BIT(6), ///< Received CMD9 from master.
SPI_EV_CMDA = BIT(7), ///< Received CMDA from master.
/* Common Event */
SPI_EV_TRANS = BIT(8), ///< A transaction has done
} spi_event_t;
FLAG_ATTR(spi_event_t)
/**
* @brief Line mode of SPI transaction phases: CMD, ADDR, DOUT/DIN.
*/
typedef struct {
uint8_t cmd_lines; ///< The line width of command phase, e.g. 2-line-cmd-phase.
uint8_t addr_lines; ///< The line width of address phase, e.g. 1-line-addr-phase.
uint8_t data_lines; ///< The line width of data phase, e.g. 4-line-data-phase.
} spi_line_mode_t;
/**
* @brief SPI command.
*/
typedef enum {
/* Slave HD Only */
SPI_CMD_HD_WRBUF = BIT(0),
SPI_CMD_HD_RDBUF = BIT(1),
SPI_CMD_HD_WRDMA = BIT(2),
SPI_CMD_HD_RDDMA = BIT(3),
SPI_CMD_HD_SEG_END = BIT(4),
SPI_CMD_HD_EN_QPI = BIT(5),
SPI_CMD_HD_WR_END = BIT(6),
SPI_CMD_HD_INT0 = BIT(7),
SPI_CMD_HD_INT1 = BIT(8),
SPI_CMD_HD_INT2 = BIT(9),
} spi_command_t;
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
//alias for different chips, deprecated for the chips after esp32s2
#ifdef CONFIG_IDF_TARGET_ESP32
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI2_HOST
#define VSPI_HOST SPI3_HOST
#elif CONFIG_IDF_TARGET_ESP32S2
// SPI_HOST (SPI1_HOST) is not supported by the SPI Master and SPI Slave driver on ESP32-S2 and later
#define SPI_HOST SPI1_HOST
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI3_HOST
#endif
/** @endcond */

View File

@@ -0,0 +1,105 @@
// 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.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/systimer_struct.h"
#include "hal/systimer_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
systimer_dev_t *dev;
} systimer_hal_context_t;
/**
* @brief initialize systimer in HAL layer
*/
void systimer_hal_init(systimer_hal_context_t *hal);
/**
* @brief enable systimer counter
*/
void systimer_hal_enable_counter(systimer_hal_context_t *hal, uint32_t counter_id);
/**
* @brief get current counter value
*/
uint64_t systimer_hal_get_counter_value(systimer_hal_context_t *hal, uint32_t counter_id);
/**
* @brief get current time (in microseconds)
*/
uint64_t systimer_hal_get_time(systimer_hal_context_t *hal, uint32_t counter_id);
/*
* @brief set alarm target value (used in one-shot mode)
*/
void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t target);
/**
* @brief set alarm period value (used in period mode)
*/
void systimer_hal_set_alarm_period(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t period);
/**
* @brief get alarm time
*/
uint64_t systimer_hal_get_alarm_value(systimer_hal_context_t *hal, uint32_t alarm_id);
/**
* @brief enable alarm interrupt
*/
void systimer_hal_enable_alarm_int(systimer_hal_context_t *hal, uint32_t alarm_id);
/**
* @brief select alarm mode
*/
void systimer_hal_select_alarm_mode(systimer_hal_context_t *hal, uint32_t alarm_id, systimer_alarm_mode_t mode);
/**
* @brief update systimer step when apb clock gets changed
*/
void systimer_hal_on_apb_freq_update(systimer_hal_context_t *hal, uint32_t apb_ticks_per_us);
/**
* @brief move systimer counter value forward or backward
*/
void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t counter_id, int64_t time_us);
/**
* @brief connect alarm unit to selected counter
*/
void systimer_hal_connect_alarm_counter(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t counter_id);
/**
* @brief set if a counter should be stalled when CPU is halted by the debugger
*/
void systimer_hal_counter_can_stall_by_cpu(systimer_hal_context_t *hal, uint32_t counter_id, uint32_t cpu_id, bool can);
#if !SOC_SYSTIMER_FIXED_TICKS_US
/**
* @brief set increase steps for systimer counter on different clock source
*/
void systimer_hal_set_steps_per_tick(systimer_hal_context_t *hal, int clock_source, uint32_t steps);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,56 @@
// 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.
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* @brief The structure of the counter value in systimer
*
*/
typedef struct {
union {
struct {
uint64_t lo : SOC_SYSTIMER_BIT_WIDTH_LO; /*!< Low part of counter value */
uint64_t hi : SOC_SYSTIMER_BIT_WIDTH_HI; /*!< High part of counter value */
#if (SOC_SYSTIMER_BIT_WIDTH_LO + SOC_SYSTIMER_BIT_WIDTH_HI) < 64
uint64_t reserved: (64 - (SOC_SYSTIMER_BIT_WIDTH_LO + SOC_SYSTIMER_BIT_WIDTH_HI));
#endif
};
uint64_t val; /*!< counter value */
};
} systimer_counter_value_t;
/** @cond */
_Static_assert(sizeof(systimer_counter_value_t) == 8, "systimer_counter_value_t should occupy 8 bytes in memory");
/** @endcond */
/**
* @brief systimer alarm mode
*
*/
typedef enum {
SYSTIMER_ALARM_MODE_ONESHOT, /*!< systimer alarm oneshot mode */
SYSTIMER_ALARM_MODE_PERIOD, /*!< systimer alarm period mode */
} systimer_alarm_mode_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,339 @@
// Copyright 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for Timer Group.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#include "hal/timer_ll.h"
#include "hal/timer_types.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
timg_dev_t *dev;
timer_idx_t idx;
} timer_hal_context_t;
/**
* @brief Init the timer hal. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param group_num The timer group number
* @param timer_num The timer number
*
* @return None
*/
void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Get interrupt status register address and corresponding control bits mask
*
* @param hal Context of the HAL layer
* @param status_reg[out] interrupt status register address
* @param mask_bit[out] control bits mask
*/
void timer_hal_get_status_reg_mask_bit(timer_hal_context_t *hal, uint32_t *status_reg, uint32_t *mask_bit);
/**
* @brief Reset timer peripheral
*
* @param hal Context of the HAL layer
*
* @return None
*/
void timer_hal_reset_periph(timer_hal_context_t *hal);
/**
* @brief Set timer clock prescale value
*
* @param hal Context of the HAL layer
* @param divider Prescale value
*
* @return None
*/
#define timer_hal_set_divider(hal, divider) timer_ll_set_divider((hal)->dev, (hal)->idx, divider)
/**
* @brief Get timer clock prescale value
*
* @param hal Context of the HAL layer
* @param divider Pointer to accept the prescale value
*
* @return None
*/
#define timer_hal_get_divider(hal, divider) timer_ll_get_divider((hal)->dev, (hal)->idx, divider)
/**
* @brief Load counter value into time-base counter
*
* @param hal Context of the HAL layer
* @param load_val Counter value
*
* @return None
*/
#define timer_hal_set_counter_value(hal, load_val) timer_ll_set_counter_value((hal)->dev, (hal)->idx, load_val)
/**
* @brief Get counter value from time-base counter
*
* @param hal Context of the HAL layer
* @param timer_val Pointer to accept the counter value
*
* @return None
*/
#define timer_hal_get_counter_value(hal, timer_val) timer_ll_get_counter_value((hal)->dev, (hal)->idx, timer_val)
/**
* @brief Set counter mode, include increment mode and decrement mode.
*
* @param hal Context of the HAL layer
* @param increase_en True to increment mode, fasle to decrement mode
*
* @return None
*/
#define timer_hal_set_counter_increase(hal, increase_en) timer_ll_set_counter_increase((hal)->dev, (hal)->idx, increase_en)
/**
* @brief Get counter mode, include increment mode and decrement mode.
*
* @param hal Context of the HAL layer
* @param counter_dir Pointer to accept the counter mode
*
* @return
* - true Increment mode
* - false Decrement mode
*/
#define timer_hal_get_counter_increase(hal) timer_ll_get_counter_increase((hal)->dev, (hal)->idx)
/**
* @brief Set counter status, enable or disable counter.
*
* @param hal Context of the HAL layer
* @param counter_en True to enable counter, false to disable counter
*
* @return None
*/
#define timer_hal_set_counter_enable(hal, counter_en) timer_ll_set_counter_enable((hal)->dev, (hal)->idx, counter_en)
/**
* @brief Get counter status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable counter
* - false Disable conuter
*/
#define timer_hal_get_counter_enable(hal) timer_ll_get_counter_enable((hal)->dev, (hal)->idx)
/**
* @brief Set auto reload mode.
*
* @param hal Context of the HAL layer
* @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
*
* @return None
*/
#define timer_hal_set_auto_reload(hal, auto_reload_en) timer_ll_set_auto_reload((hal)->dev, (hal)->idx, auto_reload_en)
/**
* @brief Get auto reload mode.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable auto reload mode
* - false Disable auto reload mode
*/
#define timer_hal_get_auto_reload(hal) timer_ll_get_auto_reload((hal)->dev, (hal)->idx)
/**
* @brief Set the counter value to trigger the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_value Counter value to trigger the alarm
*
* @return None
*/
#define timer_hal_set_alarm_value(hal, alarm_value) timer_ll_set_alarm_value((hal)->dev, (hal)->idx, alarm_value)
/**
* @brief Get the counter value to trigger the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_value Pointer to accept the counter value to trigger the alarm
*
* @return None
*/
#define timer_hal_get_alarm_value(hal, alarm_value) timer_ll_get_alarm_value((hal)->dev, (hal)->idx, alarm_value)
/**
* @brief Set the alarm status, enable or disable the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_en True to enable alarm, false to disable alarm
*
* @return None
*/
#define timer_hal_set_alarm_enable(hal, alarm_en) timer_ll_set_alarm_enable((hal)->dev, (hal)->idx, alarm_en)
/**
* @brief Get the alarm status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable alarm
* - false Disable alarm
*/
#define timer_hal_get_alarm_enable(hal) timer_ll_get_alarm_enable((hal)->dev, (hal)->idx)
/**
* @brief Set the level interrupt status, enable or disable the level interrupt.
*
* @param hal Context of the HAL layer
* @param level_int_en True to enable level interrupt, false to disable level interrupt
*
* @return None
*/
#define timer_hal_set_level_int_enable(hal, level_int_en) timer_ll_set_level_int_enable((hal)->dev, (hal)->idx, level_int_en)
/**
* @brief Get the level interrupt status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable level interrupt
* - false Disable level interrupt
*/
#define timer_hal_get_level_int_enable(hal) timer_ll_get_level_int_enable((hal)->dev, (hal)->idx)
/**
* @brief Set the edge interrupt status, enable or disable the edge interrupt.
*
* @param hal Context of the HAL layer
* @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
*
* @return None
*/
#define timer_hal_set_edge_int_enable(hal, edge_int_en) timer_ll_set_edge_int_enable((hal)->dev, (hal)->idx, edge_int_en)
/**
* @brief Get the edge interrupt status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable edge interrupt
* - false Disable edge interrupt
*/
#define timer_hal_get_edge_int_enable(hal) timer_ll_get_edge_int_enable((hal)->dev, (hal)->idx)
/**
* @brief Enable timer interrupt.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_intr_enable(hal) timer_ll_intr_enable((hal)->dev, (hal)->idx)
/**
* @brief Disable timer interrupt.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_intr_disable(hal) timer_ll_intr_disable((hal)->dev, (hal)->idx)
/**
* @brief Clear interrupt status.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_clear_intr_status(hal) timer_ll_clear_intr_status((hal)->dev, (hal)->idx)
/**
* @brief Get interrupt status.
*
* @param hal Context of the HAL layer
* @param intr_status Interrupt status
*
* @return None
*/
#define timer_hal_get_intr_status(hal, intr_status) timer_ll_get_intr_status((hal)->dev, intr_status)
/**
* @brief Get interrupt raw status.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_raw_status Interrupt raw status
*
* @return None
*/
#define timer_hal_get_intr_raw_status(group_num, intr_raw_status) timer_ll_get_intr_raw_status(group_num, intr_raw_status)
/**
* @brief Get interrupt status register address.
*
* @param hal Context of the HAL layer
*
* @return Interrupt status register address
*/
#define timer_hal_get_intr_status_reg(hal) timer_ll_get_intr_status_reg((hal)->dev)
#if SOC_TIMER_GROUP_SUPPORT_XTAL
/**
* @brief Set clock source.
*
* @param hal Context of the HAL layer
* @param use_xtal_en True to use XTAL clock, flase to use APB clock
*
* @return None
*/
#define timer_hal_set_use_xtal(hal, use_xtal_en) timer_ll_set_use_xtal((hal)->dev, (hal)->idx, use_xtal_en)
/**
* @brief Get clock source.
*
* @param hal Context of the HAL layer
*
* @return
* - true Use XTAL clock
* - false Use APB clock
*/
#define timer_hal_get_use_xtal(hal) timer_ll_get_use_xtal((hal)->dev, (hal)->idx)
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,135 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <esp_bit_defs.h>
#include "esp_attr.h"
#include "soc/soc_caps.h"
/**
* @brief Selects a Timer-Group out of 2 available groups
*/
typedef enum {
TIMER_GROUP_0 = 0, /*!<Hw timer group 0*/
#if SOC_TIMER_GROUPS > 1
TIMER_GROUP_1 = 1, /*!<Hw timer group 1*/
#endif
TIMER_GROUP_MAX,
} timer_group_t;
/**
* @brief Select a hardware timer from timer groups
*/
typedef enum {
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
#endif
TIMER_MAX,
} timer_idx_t;
/**
* @brief Decides the direction of counter
*/
typedef enum {
TIMER_COUNT_DOWN = 0, /*!< Descending Count from cnt.high|cnt.low*/
TIMER_COUNT_UP = 1, /*!< Ascending Count from Zero*/
TIMER_COUNT_MAX
} timer_count_dir_t;
/**
* @brief Decides whether timer is on or paused
*/
typedef enum {
TIMER_PAUSE = 0, /*!<Pause timer counter*/
TIMER_START = 1, /*!<Start timer counter*/
} timer_start_t;
/**
* @brief Interrupt types of the timer.
*/
//this is compatible with the value of esp32.
typedef enum {
TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */
TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */
#else
TIMER_INTR_WDT = BIT(1), /*!< interrupt of watchdog */
#endif
TIMER_INTR_NONE = 0
} timer_intr_t;
FLAG_ATTR(timer_intr_t)
/**
* @brief Decides whether to enable alarm mode
*/
typedef enum {
TIMER_ALARM_DIS = 0, /*!< Disable timer alarm*/
TIMER_ALARM_EN = 1, /*!< Enable timer alarm*/
TIMER_ALARM_MAX
} timer_alarm_t;
/**
* @brief Select interrupt type if running in alarm mode.
*/
typedef enum {
TIMER_INTR_LEVEL = 0, /*!< Interrupt mode: level mode*/
TIMER_INTR_MAX
} timer_intr_mode_t;
/**
* @brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
*/
typedef enum {
TIMER_AUTORELOAD_DIS = 0, /*!< Disable auto-reload: hardware will not load counter value after an alarm event*/
TIMER_AUTORELOAD_EN = 1, /*!< Enable auto-reload: hardware will load counter value after an alarm event*/
TIMER_AUTORELOAD_MAX,
} timer_autoreload_t;
#if SOC_TIMER_GROUP_SUPPORT_XTAL
/**
* @brief Select timer source clock.
*/
typedef enum {
TIMER_SRC_CLK_APB = 0, /*!< Select APB as the source clock*/
TIMER_SRC_CLK_XTAL = 1, /*!< Select XTAL as the source clock*/
} timer_src_clk_t;
#endif
/**
* @brief Data structure with timer's configuration settings
*/
typedef struct {
timer_alarm_t alarm_en; /*!< Timer alarm enable */
timer_start_t counter_en; /*!< Counter enable */
timer_intr_mode_t intr_type; /*!< Interrupt mode */
timer_count_dir_t counter_dir; /*!< Counter direction */
timer_autoreload_t auto_reload; /*!< Timer auto-reload */
uint32_t divider; /*!< Counter clock divider. The divider's range is from from 2 to 65536. */
#if SOC_TIMER_GROUP_SUPPORT_XTAL
timer_src_clk_t clk_src; /*!< Use XTAL as source clock. */
#endif
} timer_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,225 @@
// Copyright 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for touch sensor (common part)
#pragma once
#include "hal/touch_sensor_ll.h"
#include "hal/touch_sensor_types.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
touch_high_volt_t refh;
touch_low_volt_t refl;
touch_volt_atten_t atten;
} touch_hal_volt_t;
typedef struct {
touch_cnt_slope_t slope; /*!<Set touch sensor charge/discharge speed(currents) for each pad.*/
touch_tie_opt_t tie_opt; /*!<Set initial voltage state of touch channel for each measurement.*/
} touch_hal_meas_mode_t;
/**
* Set touch sensor sleep time (interval of measurement).
*
* @param sleep_time The touch sensor will sleep after each measurement.
* sleep_cycle decide the interval between each measurement.
* t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).
* The approximate frequency value of RTC_SLOW_CLK can be obtained using `rtc_clk_slow_freq_get_hz` function.
*/
#define touch_hal_set_sleep_time(sleep_time) touch_ll_set_sleep_time(sleep_time)
/**
* Get touch sensor sleep time.
*
* @param sleep_time Pointer to accept sleep cycle count.
*/
#define touch_hal_get_sleep_time(sleep_time) touch_ll_get_sleep_time(sleep_time)
/**
* Set touch sensor high / low voltage threshold of chanrge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So charge threshold should be less than the supply voltage.
* The actual charge threshold is high voltage threshold minus attenuation value.
*
* @param refh The high voltage threshold of chanrge.
*/
void touch_hal_set_voltage(const touch_hal_volt_t *volt);
/**
* Get touch sensor high / low voltage threshold of chanrge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So charge threshold should be less than the supply voltage.
* The actual charge threshold is high voltage threshold minus attenuation value.
*
* @param refh The voltage threshold of chanrge / discharge.
*/
void touch_hal_get_voltage(touch_hal_volt_t *volt);
/**
* Set touch sensor charge/discharge speed(currents) and initial voltage state for each pad measurement.
*
* @param touch_num Touch pad index.
* @param meas Touch pad measurement config.
*/
void touch_hal_set_meas_mode(touch_pad_t touch_num, const touch_hal_meas_mode_t *meas);
/**
* Get touch sensor charge/discharge speed(currents) and initial voltage state for each pad measurement.
*
* @param touch_num Touch pad index.
* @param meas Touch pad measurement config.
*/
void touch_hal_get_meas_mode(touch_pad_t touch_num, touch_hal_meas_mode_t *meas);
/**
* Set touch sensor FSM mode.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
#define touch_hal_set_fsm_mode(mode) touch_ll_set_fsm_mode(mode)
/**
* Get touch sensor FSM mode.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*
* @param mode FSM mode.
*/
#define touch_hal_get_fsm_mode(mode) touch_ll_get_fsm_mode(mode)
/**
* Start touch sensor FSM timer.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*/
#define touch_hal_start_fsm() touch_ll_start_fsm()
/**
* Stop touch sensor FSM timer.
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
*/
#define touch_hal_stop_fsm() touch_ll_stop_fsm()
/**
* Trigger a touch sensor measurement, only support in SW mode of FSM.
*/
#define touch_hal_start_sw_meas() touch_ll_start_sw_meas()
/**
* Set touch sensor interrupt threshold.
*
* @note Refer to `touch_pad_set_trigger_mode` to see how to set trigger mode.
* @param touch_num touch pad index.
* @param threshold threshold of touchpad count.
*/
#define touch_hal_set_threshold(touch_num, threshold) touch_ll_set_threshold(touch_num, threshold)
/**
* Get touch sensor interrupt threshold.
*
* @param touch_num touch pad index.
* @param threshold pointer to accept threshold.
*/
#define touch_hal_get_threshold(touch_num, threshold) touch_ll_get_threshold(touch_num, threshold)
/**
* Enable touch sensor channel. Register touch channel into touch sensor measurement group.
* The working mode of the touch sensor is simultaneous measurement.
* This function will set the measure bits according to the given bitmask.
*
* @note If set this mask, the FSM timer should be stop firsty.
* @note The touch sensor that in scan map, should be deinit GPIO function firstly.
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
* @return
* - ESP_OK on success
*/
#define touch_hal_set_channel_mask(enable_mask) touch_ll_set_channel_mask(enable_mask)
/**
* Get touch sensor channel mask.
*
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
*/
#define touch_hal_get_channel_mask(enable_mask) touch_ll_get_channel_mask(enable_mask)
/**
* Disable touch sensor channel by bitmask.
*
* @param enable_mask bitmask of touch sensor scan group.
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
*/
#define touch_hal_clear_channel_mask(disable_mask) touch_ll_clear_channel_mask(disable_mask)
/**
* Get the touch sensor status, usually used in ISR to decide which pads are 'touched'.
*
* @param status_mask The touch sensor status. e.g. Touch1 trigger status is `status_mask & (BIT1)`.
*/
#define touch_hal_read_trigger_status_mask(status_mask) touch_ll_read_trigger_status_mask(status_mask)
/**
* Clear all touch sensor status.
*/
#define touch_hal_clear_trigger_status_mask() touch_ll_clear_trigger_status_mask()
/**
* Get touch sensor raw data (touch sensor counter value) from register. No block.
*
* @param touch_num touch pad index.
* @return touch_value pointer to accept touch sensor value.
*/
#define touch_hal_read_raw_data(touch_num) touch_ll_read_raw_data(touch_num)
/**
* Get touch sensor measure status. No block.
*
* @return
* - If touch sensors measure done.
*/
#define touch_hal_meas_is_done() touch_ll_meas_is_done()
/**
* Initialize touch module.
*
* @note If default parameter don't match the usage scenario, it can be changed after this function.
*/
void touch_hal_init(void);
/**
* Un-install touch pad driver.
*
* @note After this function is called, other touch functions are prohibited from being called.
*/
void touch_hal_deinit(void);
/**
* Configure touch sensor for each channel.
*/
void touch_hal_config(touch_pad_t touch_num);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,292 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "sdkconfig.h"
/** Touch pad channel */
typedef enum {
TOUCH_PAD_NUM0 = 0, /*!< Touch pad channel 0 is GPIO4(ESP32) */
TOUCH_PAD_NUM1, /*!< Touch pad channel 1 is GPIO0(ESP32) / GPIO1(ESP32-S2) */
TOUCH_PAD_NUM2, /*!< Touch pad channel 2 is GPIO2(ESP32) / GPIO2(ESP32-S2) */
TOUCH_PAD_NUM3, /*!< Touch pad channel 3 is GPIO15(ESP32) / GPIO3(ESP32-S2) */
TOUCH_PAD_NUM4, /*!< Touch pad channel 4 is GPIO13(ESP32) / GPIO4(ESP32-S2) */
TOUCH_PAD_NUM5, /*!< Touch pad channel 5 is GPIO12(ESP32) / GPIO5(ESP32-S2) */
TOUCH_PAD_NUM6, /*!< Touch pad channel 6 is GPIO14(ESP32) / GPIO6(ESP32-S2) */
TOUCH_PAD_NUM7, /*!< Touch pad channel 7 is GPIO27(ESP32) / GPIO7(ESP32-S2) */
TOUCH_PAD_NUM8, /*!< Touch pad channel 8 is GPIO33(ESP32) / GPIO8(ESP32-S2) */
TOUCH_PAD_NUM9, /*!< Touch pad channel 9 is GPIO32(ESP32) / GPIO9(ESP32-S2) */
#if SOC_TOUCH_SENSOR_NUM > 10
TOUCH_PAD_NUM10, /*!< Touch channel 10 is GPIO10(ESP32-S2) */
TOUCH_PAD_NUM11, /*!< Touch channel 11 is GPIO11(ESP32-S2) */
TOUCH_PAD_NUM12, /*!< Touch channel 12 is GPIO12(ESP32-S2) */
TOUCH_PAD_NUM13, /*!< Touch channel 13 is GPIO13(ESP32-S2) */
TOUCH_PAD_NUM14, /*!< Touch channel 14 is GPIO14(ESP32-S2) */
#endif
TOUCH_PAD_MAX,
} touch_pad_t;
/** Touch sensor high reference voltage */
typedef enum {
TOUCH_HVOLT_KEEP = -1, /*!<Touch sensor high reference voltage, no change */
TOUCH_HVOLT_2V4 = 0, /*!<Touch sensor high reference voltage, 2.4V */
TOUCH_HVOLT_2V5, /*!<Touch sensor high reference voltage, 2.5V */
TOUCH_HVOLT_2V6, /*!<Touch sensor high reference voltage, 2.6V */
TOUCH_HVOLT_2V7, /*!<Touch sensor high reference voltage, 2.7V */
TOUCH_HVOLT_MAX,
} touch_high_volt_t;
/** Touch sensor low reference voltage */
typedef enum {
TOUCH_LVOLT_KEEP = -1, /*!<Touch sensor low reference voltage, no change */
TOUCH_LVOLT_0V5 = 0, /*!<Touch sensor low reference voltage, 0.5V */
TOUCH_LVOLT_0V6, /*!<Touch sensor low reference voltage, 0.6V */
TOUCH_LVOLT_0V7, /*!<Touch sensor low reference voltage, 0.7V */
TOUCH_LVOLT_0V8, /*!<Touch sensor low reference voltage, 0.8V */
TOUCH_LVOLT_MAX,
} touch_low_volt_t;
/** Touch sensor high reference voltage attenuation */
typedef enum {
TOUCH_HVOLT_ATTEN_KEEP = -1, /*!<Touch sensor high reference voltage attenuation, no change */
TOUCH_HVOLT_ATTEN_1V5 = 0, /*!<Touch sensor high reference voltage attenuation, 1.5V attenuation */
TOUCH_HVOLT_ATTEN_1V, /*!<Touch sensor high reference voltage attenuation, 1.0V attenuation */
TOUCH_HVOLT_ATTEN_0V5, /*!<Touch sensor high reference voltage attenuation, 0.5V attenuation */
TOUCH_HVOLT_ATTEN_0V, /*!<Touch sensor high reference voltage attenuation, 0V attenuation */
TOUCH_HVOLT_ATTEN_MAX,
} touch_volt_atten_t;
/** Touch sensor charge/discharge speed */
typedef enum {
TOUCH_PAD_SLOPE_0 = 0, /*!<Touch sensor charge / discharge speed, always zero */
TOUCH_PAD_SLOPE_1 = 1, /*!<Touch sensor charge / discharge speed, slowest */
TOUCH_PAD_SLOPE_2 = 2, /*!<Touch sensor charge / discharge speed */
TOUCH_PAD_SLOPE_3 = 3, /*!<Touch sensor charge / discharge speed */
TOUCH_PAD_SLOPE_4 = 4, /*!<Touch sensor charge / discharge speed */
TOUCH_PAD_SLOPE_5 = 5, /*!<Touch sensor charge / discharge speed */
TOUCH_PAD_SLOPE_6 = 6, /*!<Touch sensor charge / discharge speed */
TOUCH_PAD_SLOPE_7 = 7, /*!<Touch sensor charge / discharge speed, fast */
TOUCH_PAD_SLOPE_MAX,
} touch_cnt_slope_t;
/** Touch sensor initial charge level */
typedef enum {
TOUCH_PAD_TIE_OPT_LOW = 0, /*!<Initial level of charging voltage, low level */
TOUCH_PAD_TIE_OPT_HIGH = 1, /*!<Initial level of charging voltage, high level */
TOUCH_PAD_TIE_OPT_MAX,
} touch_tie_opt_t;
/** Touch sensor FSM mode */
typedef enum {
TOUCH_FSM_MODE_TIMER = 0, /*!<To start touch FSM by timer */
TOUCH_FSM_MODE_SW, /*!<To start touch FSM by software trigger */
TOUCH_FSM_MODE_MAX,
} touch_fsm_mode_t;
/**** ESP32 Only *****/
typedef enum {
TOUCH_TRIGGER_BELOW = 0, /*!<Touch interrupt will happen if counter value is less than threshold.*/
TOUCH_TRIGGER_ABOVE = 1, /*!<Touch interrupt will happen if counter value is larger than threshold.*/
TOUCH_TRIGGER_MAX,
} touch_trigger_mode_t;
typedef enum {
TOUCH_TRIGGER_SOURCE_BOTH = 0, /*!< wakeup interrupt is generated if both SET1 and SET2 are "touched"*/
TOUCH_TRIGGER_SOURCE_SET1 = 1, /*!< wakeup interrupt is generated if SET1 is "touched"*/
TOUCH_TRIGGER_SOURCE_MAX,
} touch_trigger_src_t;
/********************************/
#define TOUCH_PAD_BIT_MASK_ALL ((1<<SOC_TOUCH_SENSOR_NUM)-1)
#define TOUCH_PAD_SLOPE_DEFAULT (TOUCH_PAD_SLOPE_7)
#define TOUCH_PAD_TIE_OPT_DEFAULT (TOUCH_PAD_TIE_OPT_LOW)
#define TOUCH_PAD_BIT_MASK_MAX (TOUCH_PAD_BIT_MASK_ALL)
#define TOUCH_PAD_HIGH_VOLTAGE_THRESHOLD (TOUCH_HVOLT_2V7)
#define TOUCH_PAD_LOW_VOLTAGE_THRESHOLD (TOUCH_LVOLT_0V5)
#define TOUCH_PAD_ATTEN_VOLTAGE_THRESHOLD (TOUCH_HVOLT_ATTEN_0V5)
#define TOUCH_PAD_IDLE_CH_CONNECT_DEFAULT (TOUCH_PAD_CONN_GND)
#define TOUCH_PAD_THRESHOLD_MAX (SOC_TOUCH_PAD_THRESHOLD_MAX) /*!<If set touch threshold max value, The touch sensor can't be in touched status */
#ifdef CONFIG_IDF_TARGET_ESP32
#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT (0x1000) /*!<The timer frequency is RTC_SLOW_CLK (can be 150k or 32k depending on the options), max value is 0xffff */
#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (0x7fff) /*!<The timer frequency is 8Mhz, the max value is 0x7fff */
#define TOUCH_FSM_MODE_DEFAULT (TOUCH_FSM_MODE_SW) /*!<The touch FSM my be started by the software or timer */
#define TOUCH_TRIGGER_MODE_DEFAULT (TOUCH_TRIGGER_BELOW) /*!<Interrupts can be triggered if sensor value gets below or above threshold */
#define TOUCH_TRIGGER_SOURCE_DEFAULT (TOUCH_TRIGGER_SOURCE_SET1) /*!<The wakeup trigger source can be SET1 or both SET1 and SET2 */
#endif // CONFIG_IDF_TARGET ESP32
#if !CONFIG_IDF_TARGET_ESP32
/**
* Excessive total time will slow down the touch response.
* Too small measurement time will not be sampled enough, resulting in inaccurate measurements.
*
* @note The greater the duty cycle of the measurement time, the more system power is consumed.
*/
#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT (0xf) /*!<The number of sleep cycle in each measure process of touch channels.
The timer frequency is RTC_SLOW_CLK (can be 150k or 32k depending on the options).
Range: 0 ~ 0xffff */
#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (500) /*!<The times of charge and discharge in each measure process of touch channels.
The timer frequency is 8Mhz.
Recommended typical value: Modify this value to make the measurement time around 1ms.
Range: 0 ~ 0xffff */
typedef enum {
TOUCH_PAD_INTR_MASK_DONE = BIT(0), /*!<Measurement done for one of the enabled channels. */
TOUCH_PAD_INTR_MASK_ACTIVE = BIT(1), /*!<Active for one of the enabled channels. */
TOUCH_PAD_INTR_MASK_INACTIVE = BIT(2), /*!<Inactive for one of the enabled channels. */
TOUCH_PAD_INTR_MASK_SCAN_DONE = BIT(3), /*!<Measurement done for all the enabled channels. */
TOUCH_PAD_INTR_MASK_TIMEOUT = BIT(4), /*!<Timeout for one of the enabled channels. */
#if SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED
TOUCH_PAD_INTR_MASK_PROXI_MEAS_DONE = BIT(5), /*!<For proximity sensor, when the number of measurements reaches the set count of measurements, an interrupt will be generated. */
TOUCH_PAD_INTR_MASK_MAX
#define TOUCH_PAD_INTR_MASK_ALL (TOUCH_PAD_INTR_MASK_TIMEOUT \
| TOUCH_PAD_INTR_MASK_SCAN_DONE \
| TOUCH_PAD_INTR_MASK_INACTIVE \
| TOUCH_PAD_INTR_MASK_ACTIVE \
| TOUCH_PAD_INTR_MASK_DONE \
| TOUCH_PAD_INTR_MASK_PROXI_MEAS_DONE) /*!<All touch interrupt type enable. */
#else
TOUCH_PAD_INTR_MASK_MAX
#define TOUCH_PAD_INTR_MASK_ALL (TOUCH_PAD_INTR_MASK_TIMEOUT \
| TOUCH_PAD_INTR_MASK_SCAN_DONE \
| TOUCH_PAD_INTR_MASK_INACTIVE \
| TOUCH_PAD_INTR_MASK_ACTIVE \
| TOUCH_PAD_INTR_MASK_DONE) /*!<All touch interrupt type enable. */
#endif
} touch_pad_intr_mask_t;
FLAG_ATTR(touch_pad_intr_mask_t)
typedef enum {
TOUCH_PAD_DENOISE_BIT12 = 0, /*!<Denoise range is 12bit */
TOUCH_PAD_DENOISE_BIT10 = 1, /*!<Denoise range is 10bit */
TOUCH_PAD_DENOISE_BIT8 = 2, /*!<Denoise range is 8bit */
TOUCH_PAD_DENOISE_BIT4 = 3, /*!<Denoise range is 4bit */
TOUCH_PAD_DENOISE_MAX
} touch_pad_denoise_grade_t;
typedef enum {
TOUCH_PAD_DENOISE_CAP_L0 = 0, /*!<Denoise channel internal reference capacitance is 5pf */
TOUCH_PAD_DENOISE_CAP_L1 = 1, /*!<Denoise channel internal reference capacitance is 6.4pf */
TOUCH_PAD_DENOISE_CAP_L2 = 2, /*!<Denoise channel internal reference capacitance is 7.8pf */
TOUCH_PAD_DENOISE_CAP_L3 = 3, /*!<Denoise channel internal reference capacitance is 9.2pf */
TOUCH_PAD_DENOISE_CAP_L4 = 4, /*!<Denoise channel internal reference capacitance is 10.6pf */
TOUCH_PAD_DENOISE_CAP_L5 = 5, /*!<Denoise channel internal reference capacitance is 12.0pf */
TOUCH_PAD_DENOISE_CAP_L6 = 6, /*!<Denoise channel internal reference capacitance is 13.4pf */
TOUCH_PAD_DENOISE_CAP_L7 = 7, /*!<Denoise channel internal reference capacitance is 14.8pf */
TOUCH_PAD_DENOISE_CAP_MAX = 8
} touch_pad_denoise_cap_t;
/** Touch sensor denoise configuration */
typedef struct touch_pad_denoise {
touch_pad_denoise_grade_t grade; /*!<Select denoise range of denoise channel.
Determined by measuring the noise amplitude of the denoise channel. */
touch_pad_denoise_cap_t cap_level; /*!<Select internal reference capacitance of denoise channel.
Ensure that the denoise readings are closest to the readings of the channel being measured.
Use `touch_pad_denoise_read_data` to get the reading of denoise channel.
The equivalent capacitance of the shielded channel can be calculated
from the reading of denoise channel. */
} touch_pad_denoise_t;
/** Touch sensor shield channel drive capability level */
typedef enum {
TOUCH_PAD_SHIELD_DRV_L0 = 0,/*!<The max equivalent capacitance in shield channel is 40pf */
TOUCH_PAD_SHIELD_DRV_L1, /*!<The max equivalent capacitance in shield channel is 80pf */
TOUCH_PAD_SHIELD_DRV_L2, /*!<The max equivalent capacitance in shield channel is 120pf */
TOUCH_PAD_SHIELD_DRV_L3, /*!<The max equivalent capacitance in shield channel is 160pf */
TOUCH_PAD_SHIELD_DRV_L4, /*!<The max equivalent capacitance in shield channel is 200pf */
TOUCH_PAD_SHIELD_DRV_L5, /*!<The max equivalent capacitance in shield channel is 240pf */
TOUCH_PAD_SHIELD_DRV_L6, /*!<The max equivalent capacitance in shield channel is 280pf */
TOUCH_PAD_SHIELD_DRV_L7, /*!<The max equivalent capacitance in shield channel is 320pf */
TOUCH_PAD_SHIELD_DRV_MAX
} touch_pad_shield_driver_t;
/** Touch sensor waterproof configuration */
typedef struct touch_pad_waterproof {
touch_pad_t guard_ring_pad; /*!<Waterproof. Select touch channel use for guard pad.
Guard pad is used to detect the large area of water covering the touch panel. */
touch_pad_shield_driver_t shield_driver;/*!<Waterproof. Shield channel drive capability configuration.
Shield pad is used to shield the influence of water droplets covering the touch panel.
When the waterproof function is enabled, Touch14 is set as shield channel by default.
The larger the parasitic capacitance on the shielding channel, the higher the drive capability needs to be set.
The equivalent capacitance of the shield channel can be estimated through the reading value of the denoise channel(Touch0).*/
} touch_pad_waterproof_t;
/** Touch sensor proximity detection configuration */
#define TOUCH_PROXIMITY_MEAS_NUM_MAX (0xFF)
/** Touch channel idle state configuration */
typedef enum {
TOUCH_PAD_CONN_HIGHZ = 0, /*!<Idle status of touch channel is high resistance state */
TOUCH_PAD_CONN_GND = 1, /*!<Idle status of touch channel is ground connection */
TOUCH_PAD_CONN_MAX
} touch_pad_conn_type_t;
/**
* @brief Touch channel IIR filter coefficient configuration.
* @note On ESP32S2. There is an error in the IIR calculation. The magnitude of the error is twice the filter coefficient.
* So please select a smaller filter coefficient on the basis of meeting the filtering requirements.
* Recommended filter coefficient selection `IIR_16`.
*/
typedef enum {
TOUCH_PAD_FILTER_IIR_4 = 0, /*!<The filter mode is first-order IIR filter. The coefficient is 4. */
TOUCH_PAD_FILTER_IIR_8, /*!<The filter mode is first-order IIR filter. The coefficient is 8. */
TOUCH_PAD_FILTER_IIR_16, /*!<The filter mode is first-order IIR filter. The coefficient is 16 (Typical value). */
TOUCH_PAD_FILTER_IIR_32, /*!<The filter mode is first-order IIR filter. The coefficient is 32. */
TOUCH_PAD_FILTER_IIR_64, /*!<The filter mode is first-order IIR filter. The coefficient is 64. */
TOUCH_PAD_FILTER_IIR_128, /*!<The filter mode is first-order IIR filter. The coefficient is 128. */
TOUCH_PAD_FILTER_IIR_256, /*!<The filter mode is first-order IIR filter. The coefficient is 256. */
TOUCH_PAD_FILTER_JITTER, /*!<The filter mode is jitter filter */
TOUCH_PAD_FILTER_MAX
} touch_filter_mode_t;
/**
* @brief Level of filter applied on the original data against large noise interference.
* @note On ESP32S2. There is an error in the IIR calculation. The magnitude of the error is twice the filter coefficient.
* So please select a smaller filter coefficient on the basis of meeting the filtering requirements.
* Recommended filter coefficient selection `IIR_2`.
*/
typedef enum {
TOUCH_PAD_SMOOTH_OFF = 0, /*!<No filtering of raw data. */
TOUCH_PAD_SMOOTH_IIR_2 = 1, /*!<Filter the raw data. The coefficient is 2 (Typical value). */
TOUCH_PAD_SMOOTH_IIR_4 = 2, /*!<Filter the raw data. The coefficient is 4. */
TOUCH_PAD_SMOOTH_IIR_8 = 3, /*!<Filter the raw data. The coefficient is 8. */
TOUCH_PAD_SMOOTH_MAX,
} touch_smooth_mode_t;
/** Touch sensor filter configuration */
typedef struct touch_filter_config {
touch_filter_mode_t mode; /*!<Set filter mode. The input of the filter is the raw value of touch reading,
and the output of the filter is involved in the judgment of the touch state. */
uint32_t debounce_cnt; /*!<Set debounce count, such as `n`. If the measured values continue to exceed
the threshold for `n+1` times, the touch sensor state changes.
Range: 0 ~ 7 */
uint32_t noise_thr; /*!<Noise threshold coefficient. Higher = More noise resistance.
The actual noise should be less than (noise coefficient * touch threshold).
Range: 0 ~ 3. The coefficient is 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; */
uint32_t jitter_step; /*!<Set jitter filter step size. Range: 0 ~ 15 */
touch_smooth_mode_t smh_lvl;/*!<Level of filter applied on the original data against large noise interference. */
#define TOUCH_DEBOUNCE_CNT_MAX (7)
#define TOUCH_NOISE_THR_MAX (3)
#define TOUCH_JITTER_STEP_MAX (15)
} touch_filter_config_t;
/** Touch sensor channel sleep configuration */
typedef struct {
touch_pad_t touch_num; /*!<Set touch channel number for sleep pad.
Only one touch sensor channel is supported in deep sleep mode.
If clear the sleep channel, point this pad to `TOUCH_PAD_NUM0` */
bool en_proximity; /*!<enable proximity function for sleep pad */
} touch_pad_sleep_channel_t;
#endif // !CONFIG_IDF_TARGET_ESP32

View File

@@ -0,0 +1,378 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "hal/twai_types.h"
#include "hal/twai_ll.h"
/* ------------------------- Defines and Typedefs --------------------------- */
#define TWAI_HAL_SET_BITS(var, flag) ((var) |= (flag))
#define TWAI_HAL_CLEAR_BITS(var, flag) ((var) &= ~(flag))
//HAL state flags
#define TWAI_HAL_STATE_FLAG_RUNNING (1 << 0) //Controller is active (not in reset mode)
#define TWAI_HAL_STATE_FLAG_RECOVERING (1 << 1) //Bus is undergoing bus recovery
#define TWAI_HAL_STATE_FLAG_ERR_WARN (1 << 2) //TEC or REC is >= error warning limit
#define TWAI_HAL_STATE_FLAG_ERR_PASSIVE (1 << 3) //TEC or REC is >= 128
#define TWAI_HAL_STATE_FLAG_BUS_OFF (1 << 4) //Bus-off due to TEC >= 256
#define TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED (1 << 5) //Transmit buffer is occupied
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
#define TWAI_HAL_STATE_FLAG_TX_NEED_RETRY (1 << 7) //TX needs to be restarted due to errata workarounds
#endif
//Interrupt Events
#define TWAI_HAL_EVENT_BUS_OFF (1 << 0)
#define TWAI_HAL_EVENT_BUS_RECOV_CPLT (1 << 1)
#define TWAI_HAL_EVENT_BUS_RECOV_PROGRESS (1 << 2)
#define TWAI_HAL_EVENT_ABOVE_EWL (1 << 3)
#define TWAI_HAL_EVENT_BELOW_EWL (1 << 4)
#define TWAI_HAL_EVENT_ERROR_PASSIVE (1 << 5)
#define TWAI_HAL_EVENT_ERROR_ACTIVE (1 << 6)
#define TWAI_HAL_EVENT_BUS_ERR (1 << 7)
#define TWAI_HAL_EVENT_ARB_LOST (1 << 8)
#define TWAI_HAL_EVENT_RX_BUFF_FRAME (1 << 9)
#define TWAI_HAL_EVENT_TX_BUFF_FREE (1 << 10)
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
#define TWAI_HAL_EVENT_NEED_PERIPH_RESET (1 << 11)
#endif
typedef twai_ll_frame_buffer_t twai_hal_frame_t;
typedef struct {
twai_dev_t *dev;
uint32_t state_flags;
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
twai_hal_frame_t tx_frame_save;
twai_ll_reg_save_t reg_save;
uint8_t rx_msg_cnt_save;
#endif
} twai_hal_context_t;
/* ---------------------------- Init and Config ----------------------------- */
/**
* @brief Initialize TWAI peripheral and HAL context
*
* Sets HAL context, puts TWAI peripheral into reset mode, then sets some
* registers with default values.
*
* @param hal_ctx Context of the HAL layer
* @return True if successfully initialized, false otherwise.
*/
bool twai_hal_init(twai_hal_context_t *hal_ctx);
/**
* @brief Deinitialize the TWAI peripheral and HAL context
*
* Clears any unhandled interrupts and unsets HAL context
*
* @param hal_ctx Context of the HAL layer
*/
void twai_hal_deinit(twai_hal_context_t *hal_ctx);
/**
* @brief Configure the TWAI peripheral
*
* @param hal_ctx Context of the HAL layer
* @param t_config Pointer to timing configuration structure
* @param f_config Pointer to filter configuration structure
* @param intr_mask Mask of interrupts to enable
* @param clkout_divider Clock divider value for CLKOUT. Set to -1 to disable CLKOUT
*/
void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, uint32_t intr_mask, uint32_t clkout_divider);
/* -------------------------------- Actions --------------------------------- */
/**
* @brief Start the TWAI peripheral
*
* Start the TWAI peripheral by configuring its operating mode, then exiting
* reset mode so that the TWAI peripheral can participate in bus activities.
*
* @param hal_ctx Context of the HAL layer
* @param mode Operating mode
*/
void twai_hal_start(twai_hal_context_t *hal_ctx, twai_mode_t mode);
/**
* @brief Stop the TWAI peripheral
*
* Stop the TWAI peripheral by entering reset mode to stop any bus activity, then
* setting the operating mode to Listen Only so that REC is frozen.
*
* @param hal_ctx Context of the HAL layer
*/
void twai_hal_stop(twai_hal_context_t *hal_ctx);
/**
* @brief Start bus recovery
*
* @param hal_ctx Context of the HAL layer
*/
static inline void twai_hal_start_bus_recovery(twai_hal_context_t *hal_ctx)
{
TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_RECOVERING);
twai_ll_exit_reset_mode(hal_ctx->dev);
}
/**
* @brief Get the value of the TX Error Counter
*
* @param hal_ctx Context of the HAL layer
* @return TX Error Counter Value
*/
static inline uint32_t twai_hal_get_tec(twai_hal_context_t *hal_ctx)
{
return twai_ll_get_tec((hal_ctx)->dev);
}
/**
* @brief Get the value of the RX Error Counter
*
* @param hal_ctx Context of the HAL layer
* @return RX Error Counter Value
*/
static inline uint32_t twai_hal_get_rec(twai_hal_context_t *hal_ctx)
{
return twai_ll_get_rec((hal_ctx)->dev);
}
/**
* @brief Get the RX message count register
*
* @param hal_ctx Context of the HAL layer
* @return RX message count
*/
static inline uint32_t twai_hal_get_rx_msg_count(twai_hal_context_t *hal_ctx)
{
return twai_ll_get_rx_msg_count((hal_ctx)->dev);
}
/**
* @brief Check if the last transmitted frame was successful
*
* @param hal_ctx Context of the HAL layer
* @return True if successful
*/
static inline bool twai_hal_check_last_tx_successful(twai_hal_context_t *hal_ctx)
{
return twai_ll_is_last_tx_successful((hal_ctx)->dev);
}
/**
* @brief Check if certain HAL state flags are set
*
* The HAL will maintain a record of the controller's state via a set of flags.
* These flags are automatically maintained (i.e., set and reset) inside various
* HAL function calls. This function checks if certain flags are currently set.
*
* @param hal_ctx Context of the HAL layer
* @param check_flags Bit mask of flags to check
* @return True if one or more of the flags in check_flags are set
*/
static inline bool twai_hal_check_state_flags(twai_hal_context_t *hal_ctx, uint32_t check_flags)
{
return hal_ctx->state_flags & check_flags;
}
/* ----------------------------- Event Handling ----------------------------- */
/**
* @brief Get a bit mask of the events that triggered that triggered an interrupt
*
* This function should be called at the beginning of an interrupt. This function will do the following:
* - Read and clear interrupt register
* - Calculate what events have triggered the interrupt
* - Respond to low latency interrupt events
* - Bus off: Change to LOM to freeze TEC/REC. Errata 1 Fix
* - Recovery complete: Enter reset mode
* - Clear ECC and ALC so that their interrupts are re-armed
* - Update HAL state flags based on interrupts that have occurred.
* - For the ESP32, check for errata conditions. If a HW reset is required, this function
* will set the TWAI_HAL_EVENT_NEED_PERIPH_RESET event.
*
* @param hal_ctx Context of the HAL layer
* @return Bit mask of events that have occurred
*/
uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx);
/* ------------------------------- TX and RX -------------------------------- */
/**
* @brief Format a TWAI Frame
*
* This function takes a TWAI message structure (containing ID, DLC, data, and
* flags) and formats it to match the layout of the TX frame buffer.
*
* @param message Pointer to TWAI message
* @param frame Pointer to empty frame structure
*/
static inline void twai_hal_format_frame(const twai_message_t *message, twai_hal_frame_t *frame)
{
//Direct call to ll function
twai_ll_format_frame_buffer(message->identifier, message->data_length_code, message->data,
message->flags, frame);
}
/**
* @brief Parse a TWAI Frame
*
* This function takes a TWAI frame (in the format of the RX frame buffer) and
* parses it to a TWAI message (containing ID, DLC, data and flags).
*
* @param frame Pointer to frame structure
* @param message Pointer to empty message structure
*/
static inline void twai_hal_parse_frame(twai_hal_frame_t *frame, twai_message_t *message)
{
//Direct call to ll function
twai_ll_prase_frame_buffer(frame, &message->identifier, &message->data_length_code,
message->data, &message->flags);
}
/**
* @brief Copy a frame into the TX buffer and transmit
*
* This function copies a formatted TX frame into the TX buffer, and the
* transmit by setting the correct transmit command (e.g. normal, single shot,
* self RX) in the command register.
*
* @param hal_ctx Context of the HAL layer
* @param tx_frame Pointer to structure containing formatted TX frame
*/
void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame);
/**
* @brief Copy a frame from the RX buffer and release
*
* This function copies a frame from the RX buffer, then release the buffer (so
* that it loads the next frame in the RX FIFO). False is returned under the
* following conditions:
* - On the ESP32S2, false is returned if the RX buffer points to an overrun frame
* - On the ESP32, false is returned if the RX buffer points to the first overrun
* frame in the RX FIFO
*
* @param hal_ctx Context of the HAL layer
* @param rx_frame Pointer to structure to store RX frame
* @return True if a valid frame was copied and released. False if overrun.
*/
static inline bool twai_hal_read_rx_buffer_and_clear(twai_hal_context_t *hal_ctx, twai_hal_frame_t *rx_frame)
{
#ifdef SOC_TWAI_SUPPORTS_RX_STATUS
if (twai_ll_get_status(hal_ctx->dev) & TWAI_LL_STATUS_MS) {
//Release the buffer for this particular overrun frame
twai_ll_set_cmd_release_rx_buffer(hal_ctx->dev);
return false;
}
#else
if (twai_ll_get_status(hal_ctx->dev) & TWAI_LL_STATUS_DOS) {
//No need to release RX buffer as we'll be releaseing all RX frames in continuously later
return false;
}
#endif
twai_ll_get_rx_buffer(hal_ctx->dev, rx_frame);
twai_ll_set_cmd_release_rx_buffer(hal_ctx->dev);
return true;
}
#ifndef SOC_TWAI_SUPPORTS_RX_STATUS
/**
* @brief Clear the RX FIFO of overrun frames
*
* This function will clear the RX FIFO of overrun frames. The RX message count
* will return to 0 after calling this function.
*
* @param hal_ctx Context of the HAL layer
* @return Number of overrun messages cleared from RX FIFO
*/
static inline uint32_t twai_hal_clear_rx_fifo_overrun(twai_hal_context_t *hal_ctx)
{
uint32_t msg_cnt = 0;
//Note: Need to keep polling th rx message counter incase another message arrives whilst clearing
while (twai_ll_get_rx_msg_count(hal_ctx->dev) > 0) {
twai_ll_set_cmd_release_rx_buffer(hal_ctx->dev);
msg_cnt++;
}
//Set a clear data overrun command to clear the data overrun status bit
twai_ll_set_cmd_clear_data_overrun(hal_ctx->dev);
return msg_cnt;
}
#endif //SOC_TWAI_SUPPORTS_RX_STATUS
/* --------------------------- Errata Workarounds --------------------------- */
#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
/**
* @brief Prepare the peripheral for a HW reset
*
* Some HW erratas will require the peripheral be reset. This function should be
* called if twai_hal_get_events() returns the TWAI_HAL_EVENT_NEED_PERIPH_RESET event.
* Preparing for a reset involves the following:
* - Checking if a reset will cancel a TX. If so, mark that we need to retry that message after the reset
* - Save how many RX messages were lost due to this reset
* - Enter reset mode to stop any the peripheral from receiving any bus activity
* - Store the regsiter state of the peripheral
*
* @param hal_ctx Context of the HAL layer
*/
void twai_hal_prepare_for_reset(twai_hal_context_t *hal_ctx);
/**
* @brief Recover the peripheral after a HW reset
*
* This should be called after calling twai_hal_prepare_for_reset() and then
* executing the HW reset.
* Recovering the peripheral from a HW reset involves the following:
* - Restoring the previously saved register state
* - Exiting reset mode to allow receiving of bus activity
* - Retrying any TX message that was cancelled by the HW reset
*
* @param hal_ctx Context of the HAL layer
*/
void twai_hal_recover_from_reset(twai_hal_context_t *hal_ctx);
/**
* @brief Get how many RX messages were lost due to HW reset
*
* @note The number of lost RX messages are saved during twai_hal_prepare_for_reset()
*
* @param hal_ctx Context of the HAL layer
* @return uint32_t Number of RX messages lost due to HW reset
*/
static inline uint32_t twai_hal_get_reset_lost_rx_cnt(twai_hal_context_t *hal_ctx)
{
return hal_ctx->rx_msg_cnt_save;
}
#endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,148 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
/**
* @brief TWAI Constants
*/
#define TWAI_EXTD_ID_MASK 0x1FFFFFFF /**< Bit mask for 29 bit Extended Frame Format ID */
#define TWAI_STD_ID_MASK 0x7FF /**< Bit mask for 11 bit Standard Frame Format ID */
#define TWAI_FRAME_MAX_DLC 8 /**< Max data bytes allowed in TWAI */
#define TWAI_FRAME_EXTD_ID_LEN_BYTES 4 /**< EFF ID requires 4 bytes (29bit) */
#define TWAI_FRAME_STD_ID_LEN_BYTES 2 /**< SFF ID requires 2 bytes (11bit) */
#define TWAI_ERR_PASS_THRESH 128 /**< Error counter threshold for error passive */
/** @cond */ //Doxy command to hide preprocessor definitions from docs
/**
* @brief TWAI Message flags
*
* The message flags are used to indicate the type of message transmitted/received.
* Some flags also specify the type of transmission.
*/
#define TWAI_MSG_FLAG_NONE 0x00 /**< No message flags (Standard Frame Format) */
#define TWAI_MSG_FLAG_EXTD 0x01 /**< Extended Frame Format (29bit ID) */
#define TWAI_MSG_FLAG_RTR 0x02 /**< Message is a Remote Frame */
#define TWAI_MSG_FLAG_SS 0x04 /**< Transmit as a Single Shot Transmission. Unused for received. */
#define TWAI_MSG_FLAG_SELF 0x08 /**< Transmit as a Self Reception Request. Unused for received. */
#define TWAI_MSG_FLAG_DLC_NON_COMP 0x10 /**< Message's Data length code is larger than 8. This will break compliance with TWAI */
#define TWAI_BRP_MAX SOC_TWAI_BRP_MAX /**< Maximum configurable BRP value */
#define TWAI_BRP_MIN SOC_TWAI_BRP_MIN /**< Minimum configurable BRP value */
/**
* @brief Initializer macros for timing configuration structure
*
* The following initializer macros offer commonly found bit rates. These macros
* place the sample point at 80% or 67% of a bit time.
*
* @note These timing values are based on the assumption APB clock is at 80MHz
* @note The available bit rates are dependent on the chip target and revision.
*/
#if (SOC_TWAI_BRP_MAX > 256)
#define TWAI_TIMING_CONFIG_1KBITS() {.brp = 4000, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_5KBITS() {.brp = 800, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_10KBITS() {.brp = 400, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#endif
#if (SOC_TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN >= 2)
#define TWAI_TIMING_CONFIG_12_5KBITS() {.brp = 256, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_16KBITS() {.brp = 200, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_20KBITS() {.brp = 200, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#endif
#define TWAI_TIMING_CONFIG_25KBITS() {.brp = 128, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_50KBITS() {.brp = 80, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_100KBITS() {.brp = 40, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_125KBITS() {.brp = 32, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_250KBITS() {.brp = 16, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_500KBITS() {.brp = 8, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_800KBITS() {.brp = 4, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_1MBITS() {.brp = 4, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
/**
* @brief Initializer macro for filter configuration to accept all IDs
*/
#define TWAI_FILTER_CONFIG_ACCEPT_ALL() {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true}
/** @endcond */
/**
* @brief TWAI Controller operating modes
*/
typedef enum {
TWAI_MODE_NORMAL, /**< Normal operating mode where TWAI controller can send/receive/acknowledge messages */
TWAI_MODE_NO_ACK, /**< Transmission does not require acknowledgment. Use this mode for self testing */
TWAI_MODE_LISTEN_ONLY, /**< The TWAI controller will not influence the bus (No transmissions or acknowledgments) but can receive messages */
} twai_mode_t;
/**
* @brief Structure to store a TWAI message
*
* @note The flags member is deprecated
*/
typedef struct {
union {
struct {
//The order of these bits must match deprecated message flags for compatibility reasons
uint32_t extd: 1; /**< Extended Frame Format (29bit ID) */
uint32_t rtr: 1; /**< Message is a Remote Frame */
uint32_t ss: 1; /**< Transmit as a Single Shot Transmission. Unused for received. */
uint32_t self: 1; /**< Transmit as a Self Reception Request. Unused for received. */
uint32_t dlc_non_comp: 1; /**< Message's Data length code is larger than 8. This will break compliance with ISO 11898-1 */
uint32_t reserved: 27; /**< Reserved bits */
};
//Todo: Deprecate flags
uint32_t flags; /**< Deprecated: Alternate way to set bits using message flags */
};
uint32_t identifier; /**< 11 or 29 bit identifier */
uint8_t data_length_code; /**< Data length code */
uint8_t data[TWAI_FRAME_MAX_DLC]; /**< Data bytes (not relevant in RTR frame) */
} twai_message_t;
/**
* @brief Structure for bit timing configuration of the TWAI driver
*
* @note Macro initializers are available for this structure
*/
typedef struct {
uint32_t brp; /**< Baudrate prescaler (i.e., APB clock divider). Any even number from 2 to 128 for ESP32, 2 to 32768 for ESP32S2.
For ESP32 Rev 2 or later, multiples of 4 from 132 to 256 are also supported */
uint8_t tseg_1; /**< Timing segment 1 (Number of time quanta, between 1 to 16) */
uint8_t tseg_2; /**< Timing segment 2 (Number of time quanta, 1 to 8) */
uint8_t sjw; /**< Synchronization Jump Width (Max time quanta jump for synchronize from 1 to 4) */
bool triple_sampling; /**< Enables triple sampling when the TWAI controller samples a bit */
} twai_timing_config_t;
/**
* @brief Structure for acceptance filter configuration of the TWAI driver (see documentation)
*
* @note Macro initializers are available for this structure
*/
typedef struct {
uint32_t acceptance_code; /**< 32-bit acceptance code */
uint32_t acceptance_mask; /**< 32-bit acceptance mask */
bool single_filter; /**< Use Single Filter Mode (see documentation) */
} twai_filter_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,491 @@
// 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.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for UART.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "hal/uart_ll.h"
#include "hal/uart_types.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
uart_dev_t *dev;
} uart_hal_context_t;
/**
* @brief Clear the UART interrupt status
*
* @param hal Context of the HAL layer
* @param mask The interrupt status mask to be cleared. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET`
*
* @return None
*/
#define uart_hal_clr_intsts_mask(hal, mask) uart_ll_clr_intsts_mask((hal)->dev, mask)
/**
* @brief Disable the UART interrupt
*
* @param hal Context of the HAL layer
* @param mask The interrupt mask to be disabled. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET`
*
* @return None
*/
#define uart_hal_disable_intr_mask(hal, mask) uart_ll_disable_intr_mask((hal)->dev, mask)
/**
* @brief Enable the UART interrupt
*
* @param hal Context of the HAL layer
* @param mask The UART interrupt mask to be enabled. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET`
*
* @return None
*/
#define uart_hal_ena_intr_mask(hal, mask) uart_ll_ena_intr_mask((hal)->dev, mask)
/**
* @brief Get the UART interrupt status
*
* @param hal Context of the HAL layer
*
* @return UART interrupt status
*/
#define uart_hal_get_intsts_mask(hal) uart_ll_get_intsts_mask((hal)->dev)
/**
* @brief Get status of enabled interrupt
*
* @param hal Context of the HAL layer
*
* @return UART Interrupt enabled value
*/
#define uart_hal_get_intr_ena_status(hal) uart_ll_get_intr_ena_status((hal)->dev)
/**
* @brief Get the UART pattern char configuration
*
* @param hal Context of the HAL layer
* @param cmd_char Pointer to accept UART AT cmd char
* @param char_num Pointer to accept the `UART_CHAR_NUM` configuration
*
* @return None
*/
#define uart_hal_get_at_cmd_char(hal, cmd_char, char_num) uart_ll_get_at_cmd_char((hal)->dev, cmd_char, char_num)
/**
* @brief Set the UART rst signal active level
*
* @param hal Context of the HAL layer
* @param active_level The rts active level. The active level is low if set to 0. The active level is high if set to 1
*
* @return None
*/
#define uart_hal_set_rts(hal, active_level) uart_ll_set_rts_active_level((hal)->dev, active_level)
/**
* @brief Get the txfifo writeable length(in byte)
*
* @param hal Context of the HAL layer
*
* @return UART txfifo writeable length
*/
#define uart_hal_get_txfifo_len(hal) uart_ll_get_txfifo_len((hal)->dev)
/**
* @brief Check if the UART sending state machine is in the IDLE state.
*
* @param hal Context of the HAL layer
*
* @return True if the state machine is in the IDLE state, otherwise false will be returned.
*/
#define uart_hal_is_tx_idle(hal) uart_ll_is_tx_idle((hal)->dev)
/**
* @brief Configure the UART core reset
*
* @param hal Context of the HAL layer
* @param Set true to enable the core reset, otherwise set it false
*
* @return None
*/
#define uart_hal_set_reset_core(hal, core_rst_en) uart_ll_set_reset_core((hal)->dev, core_rst_en)
/**
* @brief Read data from the UART rxfifo
*
* @param[in] hal Context of the HAL layer
* @param[in] buf Pointer to the buffer used to store the read data. The buffer size should be large than 128 byte
* @param[inout] inout_rd_len As input, the size of output buffer to read (set to 0 to read all available data).
* As output, returns the actual size written into the output buffer.
*
* @return None
*/
void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *inout_rd_len);
/**
* @brief Write data into the UART txfifo
*
* @param hal Context of the HAL layer
* @param buf Pointer of the data buffer need to be written to txfifo
* @param data_size The data size(in byte) need to be written
* @param write_size The size has been written
*
* @return None
*/
void uart_hal_write_txfifo(uart_hal_context_t *hal, const uint8_t *buf, uint32_t data_size, uint32_t *write_size);
/**
* @brief Reset the UART txfifo
* @note On ESP32, this function is reserved for UART1 and UART2.
*
* @param hal Context of the HAL layer
*
* @return None
*/
void uart_hal_txfifo_rst(uart_hal_context_t *hal);
/**
* @brief Reset the UART rxfifo
*
* @param hal Context of the HAL layer
*
* @return None
*/
void uart_hal_rxfifo_rst(uart_hal_context_t *hal);
/**
* @brief Init the UART hal and set the UART to the default configuration.
*
* @param hal Context of the HAL layer
* @param uart_num The uart port number, the max port number is (UART_NUM_MAX -1)
*
* @return None
*/
void uart_hal_init(uart_hal_context_t *hal, uart_port_t uart_num);
/**
* @brief Set the UART source clock type
* @param hal Context of the HAL layer
* @param sclk The UART source clock type.
*
* @return None
*/
void uart_hal_set_sclk(uart_hal_context_t *hal, uart_sclk_t sclk);
/**
* @brief Get the UART source clock type
*
* @param hal Context of the HAL layer
* @param sclk The poiter to accept the UART source clock type
*
* @return None
*/
void uart_hal_get_sclk(uart_hal_context_t *hal, uart_sclk_t *sclk);
/**
* @brief Configure the UART baud-rate and select the source clock
*
* @param hal Context of the HAL layer
* @param baud_rate The baud-rate to be set
*
* @return None
*/
void uart_hal_set_baudrate(uart_hal_context_t *hal, uint32_t baud_rate);
/**
* @brief Configure the UART stop bit
*
* @param hal Context of the HAL layer
* @param stop_bit The stop bit to be set
*
* @return None
*/
void uart_hal_set_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t stop_bit);
/**
* @brief Configure the UART data bit
*
* @param hal Context of the HAL layer
* @param data_bit The data bit to be set
*
* @return None
*/
void uart_hal_set_data_bit_num(uart_hal_context_t *hal, uart_word_length_t data_bit);
/**
* @brief Configure the UART parity mode
*
* @param hal Context of the HAL layer
* @param parity_mode The UART parity mode to be set
*
* @return None
*/
void uart_hal_set_parity(uart_hal_context_t *hal, uart_parity_t parity_mode);
/**
* @brief Configure the UART hardware flow control
*
* @param hal Context of the HAL layer
* @param flow_ctrl The flow control mode to be set
* @param rx_thresh The rts flow control signal will be active if the data length in rxfifo is large than this value
*
* @return None
*/
void uart_hal_set_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
/**
* @brief Configure the UART AT cmd char detect function. When the receiver receives a continuous AT cmd char, it will produce a interrupt
*
* @param hal Context of the HAL layer
* @param at_cmd The AT cmd char detect configuration
*
* @return None.
*/
void uart_hal_set_at_cmd_char(uart_hal_context_t *hal, uart_at_cmd_t *at_cmd);
/**
* @brief Set the timeout value of the UART receiver
*
* @param hal Context of the HAL layer
* @param tout The timeout value for receiver to receive a data
*
* @return None
*/
void uart_hal_set_rx_timeout(uart_hal_context_t *hal, const uint8_t tout);
/**
* @brief Set the UART dtr signal active level
*
* @param hal Context of the HAL layer
* @param active_level The dtr active level. The active level is low if set to 0. The active level is high if set to 1
*
* @return None
*/
void uart_hal_set_dtr(uart_hal_context_t *hal, int active_level);
/**
* @brief Set the UART software flow control
*
* @param hal Context of the HAL layer
* @param flow_ctrl The software flow control configuration
* @param sw_flow_ctrl_en Set true to enable the software flow control, otherwise set it false
*
* @return None
*/
void uart_hal_set_sw_flow_ctrl(uart_hal_context_t *hal, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en);
/**
* @brief Set the UART tx idle number
*
* @param hal Context of the HAL layer
* @param idle_num The cycle number betwin the two transmission
*
* @return None
*/
void uart_hal_set_tx_idle_num(uart_hal_context_t *hal, uint16_t idle_num);
/**
* @brief Set the UART rxfifo full threshold
*
* @param hal Context of the HAL layer
* @param full_thrhd The rxfifo full threshold. If the `UART_RXFIFO_FULL` interrupt is enabled and
* the data length in rxfifo is more than this value, it will generate `UART_RXFIFO_FULL` interrupt
*
* @return None
*/
void uart_hal_set_rxfifo_full_thr(uart_hal_context_t *hal, uint32_t full_thrhd);
/**
* @brief Set the UART txfifo empty threshold
*
* @param hal Context of the HAL layer
* @param empty_thrhd The txfifo empty threshold to be set. If the `UART_TXFIFO_EMPTY` interrupt is enabled and
* the data length in txfifo is less than this value, it will generate `UART_TXFIFO_EMPTY` interrupt
*
* @return None
*/
void uart_hal_set_txfifo_empty_thr(uart_hal_context_t *hal, uint32_t empty_thrhd);
/**
* @brief Configure the UART to send a number of break(NULL) chars
*
* @param hal Context of the HAL layer
* @param break_num The number of the break char need to be send
*
* @return None
*/
void uart_hal_tx_break(uart_hal_context_t *hal, uint32_t break_num);
/**
* @brief Configure the UART wake up function.
* Note that RXD cannot be input through GPIO Matrix but only through IO_MUX when use this function
*
* @param hal Context of the HAL layer
* @param wakeup_thrd The wake up threshold to be set. The system will be woken up from light-sleep when the input RXD edge changes more times than `wakeup_thrd+2`
*
* @return None
*/
void uart_hal_set_wakeup_thrd(uart_hal_context_t *hal, uint32_t wakeup_thrd);
/**
* @brief Configure the UART mode
*
* @param hal Context of the HAL layer
* @param mode The UART mode to be set
*
* @return None
*/
void uart_hal_set_mode(uart_hal_context_t *hal, uart_mode_t mode);
/**
* @brief Configure the UART hardware to inverse the signals
*
* @param hal Context of the HAL layer
* @param inv_mask The sigal mask needs to be inversed. Use the ORred mask of type `uart_signal_inv_t`
*
* @return None
*/
void uart_hal_inverse_signal(uart_hal_context_t *hal, uint32_t inv_mask);
/**
* @brief Get the UART wakeup threshold configuration
*
* @param hal Context of the HAL layer
* @param wakeup_thrd Pointer to accept the value of UART wakeup threshold configuration
*
* @return None
*/
void uart_hal_get_wakeup_thrd(uart_hal_context_t *hal, uint32_t *wakeup_thrd);
/**
* @brief Get the UART data bit configuration
*
* @param hal Context of the HAL layer
* @param data_bit Pointer to accept the value of UART data bit configuration
*
* @return None
*/
void uart_hal_get_data_bit_num(uart_hal_context_t *hal, uart_word_length_t *data_bit);
/**
* @brief Get the UART stop bit configuration
*
* @param hal Context of the HAL layer
* @param stop_bit Pointer to accept the value of UART stop bit configuration
*
* @return None
*/
void uart_hal_get_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t *stop_bit);
/**
* @brief Get the UART parity mode configuration
*
* @param hal Context of the HAL layer
* @param parity_mode Pointer to accept the UART parity mode configuration
*
* @return None
*/
void uart_hal_get_parity(uart_hal_context_t *hal, uart_parity_t *parity_mode);
/**
* @brief Get the UART baud-rate configuration
*
* @param hal Context of the HAL layer
* @param baud_rate Pointer to accept the current baud-rate
*
* @return None
*/
void uart_hal_get_baudrate(uart_hal_context_t *hal, uint32_t *baud_rate);
/**
* @brief Get the hw flow control configuration
*
* @param hal Context of the HAL layer
* @param flow_ctrl Pointer to accept the UART flow control configuration
*
* @return None
*/
void uart_hal_get_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t *flow_ctrl);
/**
* @brief Check if the UART rts flow control is enabled
*
* @param hal Context of the HAL layer
*
* @return True if rts flow control is enabled, otherwise false will be returned
*/
bool uart_hal_is_hw_rts_en(uart_hal_context_t *hal);
/**
* @brief Configure TX signal loop back to RX module, just for the testing purposes
*
* @param hal Context of the HAL layer
* @param loop_back_en Set ture to enable the loop back function, else set it false.
*
* @return None
*/
void uart_hal_set_loop_back(uart_hal_context_t *hal, bool loop_back_en);
/**
* @brief Calculate uart symbol bit length, as defined in configuration.
*
* @param hw Beginning address of the peripheral registers.
*
* @return number of bits per UART symbol.
*/
uint8_t uart_hal_get_symb_len(uart_hal_context_t *hal);
/**
* @brief Get UART maximum timeout threshold.
*
* @param hw Beginning address of the peripheral registers.
*
* @return maximum timeout threshold value for target.
*/
uint16_t uart_hal_get_max_rx_timeout_thrd(uart_hal_context_t *hal);
/**
* @brief Get the timeout threshold value set for receiver.
*
* @param hw Beginning address of the peripheral registers.
*
* @return tout_thr The timeout value. If timeout is disabled then returns 0.
*/
#define uart_hal_get_rx_tout_thr(hal) uart_ll_get_rx_tout_thr((hal)->dev)
/**
* @brief Get the length of readable data in UART rxfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The readable data length in rxfifo.
*/
#define uart_hal_get_rxfifo_len(hal) uart_ll_get_rxfifo_len((hal)->dev)
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,154 @@
// 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
/**
* @brief UART port number, can be UART_NUM_0 ~ (UART_NUM_MAX -1).
*/
typedef int uart_port_t;
/**
* @brief UART mode selection
*/
typedef enum {
UART_MODE_UART = 0x00, /*!< mode: regular UART mode*/
UART_MODE_RS485_HALF_DUPLEX = 0x01, /*!< mode: half duplex RS485 UART mode control by RTS pin */
UART_MODE_IRDA = 0x02, /*!< mode: IRDA UART mode*/
UART_MODE_RS485_COLLISION_DETECT = 0x03, /*!< mode: RS485 collision detection UART mode (used for test purposes)*/
UART_MODE_RS485_APP_CTRL = 0x04, /*!< mode: application control RS485 UART mode (used for test purposes)*/
} uart_mode_t;
/**
* @brief UART word length constants
*/
typedef enum {
UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/
UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/
UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/
UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/
UART_DATA_BITS_MAX = 0x4,
} uart_word_length_t;
/**
* @brief UART stop bits number
*/
typedef enum {
UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/
UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/
UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/
UART_STOP_BITS_MAX = 0x4,
} uart_stop_bits_t;
/**
* @brief UART parity constants
*/
typedef enum {
UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/
UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/
UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/
} uart_parity_t;
/**
* @brief UART hardware flow control modes
*/
typedef enum {
UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/
UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/
UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/
UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/
UART_HW_FLOWCTRL_MAX = 0x4,
} uart_hw_flowcontrol_t;
/**
* @brief UART signal bit map
*/
typedef enum {
UART_SIGNAL_INV_DISABLE = 0, /*!< Disable UART signal inverse*/
UART_SIGNAL_IRDA_TX_INV = (0x1 << 0), /*!< inverse the UART irda_tx signal*/
UART_SIGNAL_IRDA_RX_INV = (0x1 << 1), /*!< inverse the UART irda_rx signal*/
UART_SIGNAL_RXD_INV = (0x1 << 2), /*!< inverse the UART rxd signal*/
UART_SIGNAL_CTS_INV = (0x1 << 3), /*!< inverse the UART cts signal*/
UART_SIGNAL_DSR_INV = (0x1 << 4), /*!< inverse the UART dsr signal*/
UART_SIGNAL_TXD_INV = (0x1 << 5), /*!< inverse the UART txd signal*/
UART_SIGNAL_RTS_INV = (0x1 << 6), /*!< inverse the UART rts signal*/
UART_SIGNAL_DTR_INV = (0x1 << 7), /*!< inverse the UART dtr signal*/
} uart_signal_inv_t;
/**
* @brief UART source clock
*/
typedef enum {
UART_SCLK_APB = 0x0, /*!< UART source clock from APB*/
#if SOC_UART_SUPPORT_RTC_CLK
UART_SCLK_RTC = 0x1, /*!< UART source clock from RTC*/
#endif
#if SOC_UART_SUPPORT_XTAL_CLK
UART_SCLK_XTAL = 0x2, /*!< UART source clock from XTAL*/
#endif
#if SOC_UART_SUPPORT_REF_TICK
UART_SCLK_REF_TICK = 0x3, /*!< UART source clock from REF_TICK*/
#endif
} uart_sclk_t;
/**
* @brief UART AT cmd char configuration parameters
* Note that this function may different on different chip. Please refer to the TRM at confirguration.
*/
typedef struct {
uint8_t cmd_char; /*!< UART AT cmd char*/
uint8_t char_num; /*!< AT cmd char repeat number*/
uint32_t gap_tout; /*!< gap time(in baud-rate) between AT cmd char*/
uint32_t pre_idle; /*!< the idle time(in baud-rate) between the non AT char and first AT char*/
uint32_t post_idle; /*!< the idle time(in baud-rate) between the last AT char and the none AT char*/
} uart_at_cmd_t;
/**
* @brief UART software flow control configuration parameters
*/
typedef struct {
uint8_t xon_char; /*!< Xon flow control char*/
uint8_t xoff_char; /*!< Xoff flow control char*/
uint8_t xon_thrd; /*!< If the software flow control is enabled and the data amount in rxfifo is less than xon_thrd, an xon_char will be sent*/
uint8_t xoff_thrd; /*!< If the software flow control is enabled and the data amount in rxfifo is more than xoff_thrd, an xoff_char will be sent*/
} uart_sw_flowctrl_t;
/**
* @brief UART configuration parameters for uart_param_config function
*/
typedef struct {
int baud_rate; /*!< UART baud rate*/
uart_word_length_t data_bits; /*!< UART byte size*/
uart_parity_t parity; /*!< UART parity mode*/
uart_stop_bits_t stop_bits; /*!< UART stop bits*/
uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/
uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/
union {
uart_sclk_t source_clk; /*!< UART source clock selection */
bool use_ref_tick __attribute__((deprecated)); /*!< Deprecated method to select ref tick clock source, set source_clk field instead */
};
} uart_config_t;
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More