Initial Esp32c3 Support (#5060)

This commit is contained in:
Me No Dev
2021-04-14 18:10:05 +03:00
committed by GitHub
parent 371f382db7
commit 404a31f445
1929 changed files with 382833 additions and 190 deletions

View File

@ -0,0 +1,119 @@
// 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
******************************************************************************/
// The HAL layer for ADC (esp32s2 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
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* Digital controller deinitialization.
*/
void adc_hal_digi_deinit(void);
/**
* Setting the digital controller.
*
* @param cfg Pointer to digital controller paramter.
*/
void adc_hal_digi_controller_config(const adc_digi_config_t *cfg);
/**
* Reset adc digital controller filter.
*
* @param filter_idx ADC filter unit.
*/
#define adc_hal_digi_filter_reset(filter_idx) adc_ll_digi_filter_reset(filter_idx)
/**
* Set adc digital controller filter factor.
*
* @param filter_idx ADC filter unit.
* @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
void adc_hal_digi_filter_set_factor(adc_digi_filter_idx_t filter_idx, adc_digi_filter_t *filter);
/**
* Get adc digital controller filter factor.
*
* @param filter_idx ADC filter unit.
* @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
void adc_hal_digi_filter_get_factor(adc_digi_filter_idx_t filter_idx, adc_digi_filter_t *filter);
/**
* Enable/disable adc digital controller filter.
* Filtering the ADC data to obtain smooth data at higher sampling rates.
*
* @note The filter will filter all the enabled channel data of the each ADC unit at the same time.
* @param filter_idx ADC filter unit.
* @param enable True to enable the filter, otherwise disable.
*/
void adc_hal_digi_filter_enable(adc_digi_filter_idx_t filter_idx, bool enable);
/**
* Config monitor of adc digital controller.
*
* @note If the channel info is not supported, the monitor function will not be enabled.
* @param mon_idx ADC monitor index.
* @param config Refer to `adc_digi_monitor_t`.
*/
void adc_hal_digi_monitor_config(adc_digi_monitor_idx_t mon_idx, adc_digi_monitor_t *config);
/**
* Enable/disable monitor of adc digital controller.
*
* @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
* @param mon_idx ADC monitor index.
* @param enable True to enable the monitor, otherwise disable.
*/
void adc_hal_digi_monitor_enable(adc_digi_monitor_idx_t mon_idx, bool enable);
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* 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);
#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 (0)
#define SOC_ADC2_DATA_INVERT_DEFAULT (0)
#define SOC_ADC_DIGI_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
#define SOC_ADC_FSM_RSTB_WAIT_DEFAULT (8)
#define SOC_ADC_FSM_START_WAIT_DEFAULT (5)
#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) ((PERIPH_NUM==0)? 2 : 1)
#define SOC_ADC_DIGI_SAR_CLK_DIV_DEFAULT (1)

View File

@ -0,0 +1,801 @@
// 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
#include <stdbool.h>
#include <stdlib.h>
#include "regi2c_ctrl.h"
#include "esp_attr.h"
#include "soc/adc_periph.h"
#include "hal/adc_types.h"
#include "soc/apb_saradc_struct.h"
#include "soc/apb_saradc_reg.h"
#include "soc/rtc_cntl_struct.h"
#include "soc/rtc_cntl_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15
#define ADC_LL_CLKM_DIV_B_DEFAULT 1
#define ADC_LL_CLKM_DIV_A_DEFAULT 0
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 controled by FSM. Used for polling mode */
ADC_POWER_SW_ON, /*!< ADC XPD controled by SW. power on. Used for DMA mode */
ADC_POWER_SW_OFF, /*!< ADC XPD controled by SW. power off. */
ADC_POWER_MAX, /*!< For parameter check. */
} adc_ll_power_t;
typedef enum {
ADC_RTC_DATA_OK = 0,
ADC_RTC_CTRL_UNSELECTED = 1,
ADC_RTC_CTRL_BREAK = 2,
ADC_RTC_DATA_FAIL = -1,
} adc_ll_rtc_raw_data_t;
//These values should be set according to the HW
typedef enum {
ADC_LL_INTR_THRES1_LOW = BIT(26),
ADC_LL_INTR_THRES0_LOW = BIT(27),
ADC_LL_INTR_THRES1_HIGH = BIT(28),
ADC_LL_INTR_THRES0_HIGH = BIT(29),
ADC_LL_INTR_ADC2_DONE = BIT(30),
ADC_LL_INTR_ADC1_DONE = BIT(31),
} adc_ll_intr_t;
FLAG_ATTR(adc_ll_intr_t)
/**
* @brief ADC controller type selection.
*
* @note For ADC2, use the force option with care. The system power consumption detection will use ADC2.
* If it is forced to switch to another controller, it may cause the system to obtain incorrect values.
* @note Normally, there is no need to switch the controller manually.
*/
typedef enum {
ADC_CTRL_RTC = 0, /*!<For ADC1. Select RTC controller. For ADC2. The controller is selected by the arbiter. Arbiter in default mode. */
ADC_CTRL_DIG = 2, /*!<For ADC1. Select DIG controller. For ADC2. The controller is selected by the arbiter. Arbiter in default mode. */
ADC2_CTRL_PWDET = 3,/*!<For ADC2. The controller is selected by the arbiter. Arbiter in default mode. */
ADC2_CTRL_FORCE_PWDET = 3, /*!<For ADC2. Arbiter in shield mode. Force select Wi-Fi controller work. */
ADC2_CTRL_FORCE_RTC = 4, /*!<For ADC2. Arbiter in shield mode. Force select RTC controller work. */
ADC2_CTRL_FORCE_DIG = 6, /*!<For ADC2. Arbiter in shield mode. Force select digital controller work. */
} adc_ll_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
APB_SARADC.fsm_wait.rstb_wait = rst_wait;
// Internal FSM start wait time
APB_SARADC.fsm_wait.xpd_wait = start_wait;
// Internal FSM standby wait time
APB_SARADC.fsm_wait.standby_wait = standby_wait;
}
/**
* Set adc sample cycle for digital controller.
*
* @note Normally, please use default value.
* @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor.
* Range: 2 ~ 0xFF.
*/
static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle)
{
/* Should be called before writing I2C registers. */
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle);
}
/**
* Set SAR ADC module clock division factor.
* SAR ADC clock divided from digital controller clock.
*
* @param div Division factor.
*/
static inline void adc_ll_digi_set_clk_div(uint32_t div)
{
/* ADC clock devided from digital controller clock clk */
APB_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)
{
APB_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)
{
APB_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)
{
APB_SARADC.ctrl2.meas_num_limit = 0;
}
/**
* Set pattern table length for digital controller.
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 items, in which channel selection,
* 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 8 different rules before repeating itself.
*
* @param adc_n ADC unit.
* @param patt_len Items range: 1 ~ 8.
*/
static inline void adc_ll_digi_set_pattern_table_len(adc_ll_num_t adc_n, uint32_t patt_len)
{
APB_SARADC.ctrl.sar_patt_len = patt_len - 1;
}
/**
* Set pattern table for digital controller.
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 8 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 8 different rules before repeating itself.
*
* @param adc_n ADC unit.
* @param pattern_index Items index. Range: 0 ~ 7.
* @param pattern Stored conversion rules.
*/
static inline void adc_ll_digi_set_pattern_table(adc_ll_num_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
{
uint32_t tab;
uint8_t index = pattern_index / 4;
uint8_t offset = (pattern_index % 4) * 6;
tab = APB_SARADC.sar_patt_tab[index].sar_patt_tab1; // Read old register value
tab &= (~(0xFC0000 >> offset)); // Clear old data
tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; // Fill in the new data
APB_SARADC.sar_patt_tab[index].sar_patt_tab1 = 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)
{
APB_SARADC.ctrl.sar_patt_p_clear = 1;
APB_SARADC.ctrl.sar_patt_p_clear = 0;
}
/**
* Sets the number of cycles required for the conversion to complete and wait for the arbiter to stabilize.
*
* @note Only ADC2 have arbiter function.
* @param cycle range: 0 ~ 4.
*/
static inline void adc_ll_digi_set_arbiter_stable_cycle(uint32_t cycle)
{
APB_SARADC.ctrl.wait_arb_cycle = cycle;
}
/**
* ADC Digital controller output data invert or not.
*
* @param adc_n ADC unit.
* @param inv_en data invert or not.
*/
static inline void adc_ll_digi_output_invert(adc_ll_num_t adc_n, bool inv_en)
{
if (adc_n == ADC_NUM_1) {
APB_SARADC.ctrl2.sar1_inv = inv_en; // Enable / Disable ADC data invert
} else { // adc_n == ADC_NUM_2
APB_SARADC.ctrl2.sar2_inv = inv_en; // Enable / Disable ADC data invert
}
}
/**
* Set the interval clock cycle for the digital controller to trigger the measurement.
* Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval.
*
* @note The trigger interval should not be smaller than the sampling time of the SAR ADC.
* @param cycle The clock cycle (trigger interval) of the measurement. Range: 30 ~ 4095.
*/
static inline void adc_ll_digi_set_trigger_interval(uint32_t cycle)
{
APB_SARADC.ctrl2.timer_target = cycle;
}
/**
* Enable digital controller timer to trigger the measurement.
*/
static inline void adc_ll_digi_trigger_enable(void)
{
APB_SARADC.ctrl2.timer_en = 1;
}
/**
* Disable digital controller timer to trigger the measurement.
*/
static inline void adc_ll_digi_trigger_disable(void)
{
APB_SARADC.ctrl2.timer_en = 0;
}
/**
* Set ADC digital controller clock division factor. The clock divided from `APLL` or `APB` clock.
* Expression: controller_clk = APLL/APB * (div_num + div_b / div_a).
*
* @param div_num Division factor. Range: 1 ~ 255.
* @param div_b Division factor. Range: 1 ~ 63.
* @param div_a Division factor. Range: 0 ~ 63.
*/
static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div_b, uint32_t div_a)
{
APB_SARADC.apb_adc_clkm_conf.clkm_div_num = div_num;
APB_SARADC.apb_adc_clkm_conf.clkm_div_b = div_b;
APB_SARADC.apb_adc_clkm_conf.clkm_div_a = div_a;
}
/**
* Enable clock and select clock source for ADC digital controller.
*
* @param use_apll true: use APLL clock; false: use APB clock.
*/
static inline void adc_ll_digi_controller_clk_enable(bool use_apll)
{
if (use_apll) {
APB_SARADC.apb_adc_clkm_conf.clk_sel = 1; // APLL clock
} else {
APB_SARADC.apb_adc_clkm_conf.clk_sel = 2; // APB clock
}
APB_SARADC.ctrl.sar_clk_gated = 1;
}
/**
* Disable clock for ADC digital controller.
*/
static inline void adc_ll_digi_controller_clk_disable(void)
{
APB_SARADC.ctrl.sar_clk_gated = 0;
}
/**
* Reset adc digital controller filter.
*
* @param adc_n ADC unit.
*/
static inline void adc_ll_digi_filter_reset(adc_ll_num_t adc_n)
{
APB_SARADC.filter_ctrl0.filter_reset = 1;
}
/**
* Set adc digital controller filter factor.
*
* @note If the channel info is not supported, the filter function will not be enabled.
* @param idx ADC filter unit.
* @param filter Filter config. Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
static inline void adc_ll_digi_filter_set_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter)
{
if (idx == ADC_DIGI_FILTER_IDX0) {
APB_SARADC.filter_ctrl0.filter_channel0 = (filter->adc_unit << 3) | (filter->channel & 0x7);
APB_SARADC.filter_ctrl1.filter_factor0 = filter->mode;
} else if (idx == ADC_DIGI_FILTER_IDX1) {
APB_SARADC.filter_ctrl0.filter_channel1 = (filter->adc_unit << 3) | (filter->channel & 0x7);
APB_SARADC.filter_ctrl1.filter_factor1 = filter->mode;
}
}
/**
* Get adc digital controller filter factor.
*
* @param adc_n ADC unit.
* @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
static inline void adc_ll_digi_filter_get_factor(adc_digi_filter_idx_t idx, adc_digi_filter_t *filter)
{
if (idx == ADC_DIGI_FILTER_IDX0) {
filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel0 >> 3) & 0x1;
filter->channel = APB_SARADC.filter_ctrl0.filter_channel0 & 0x7;
filter->mode = APB_SARADC.filter_ctrl1.filter_factor0;
} else if (idx == ADC_DIGI_FILTER_IDX1) {
filter->adc_unit = (APB_SARADC.filter_ctrl0.filter_channel1 >> 3) & 0x1;
filter->channel = APB_SARADC.filter_ctrl0.filter_channel1 & 0x7;
filter->mode = APB_SARADC.filter_ctrl1.filter_factor1;
}
}
/**
* Disable adc digital controller filter.
* Filtering the ADC data to obtain smooth data at higher sampling rates.
*
* @note If the channel info is not supported, the filter function will not be enabled.
* @param adc_n ADC unit.
*/
static inline void adc_ll_digi_filter_disable(adc_digi_filter_idx_t idx)
{
if (idx == ADC_DIGI_FILTER_IDX0) {
APB_SARADC.filter_ctrl0.filter_channel0 = 0xF;
APB_SARADC.filter_ctrl1.filter_factor0 = 0;
} else if (idx == ADC_DIGI_FILTER_IDX1) {
APB_SARADC.filter_ctrl0.filter_channel1 = 0xF;
APB_SARADC.filter_ctrl1.filter_factor1 = 0;
}
}
/**
* Set monitor mode of adc digital controller.
*
* @note If the channel info is not supported, the monitor function will not be enabled.
* @param adc_n ADC unit.
* @param is_larger true: If ADC_OUT > threshold, Generates monitor interrupt.
* false: If ADC_OUT < threshold, Generates monitor interrupt.
*/
static inline void adc_ll_digi_monitor_set_mode(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *cfg)
{
if (idx == ADC_DIGI_MONITOR_IDX0) {
APB_SARADC.thres0_ctrl.thres0_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7);
APB_SARADC.thres0_ctrl.thres0_high = cfg->h_threshold;
APB_SARADC.thres0_ctrl.thres0_low = cfg->l_threshold;
} else { // ADC_DIGI_MONITOR_IDX1
APB_SARADC.thres1_ctrl.thres1_channel = (cfg->adc_unit << 3) | (cfg->channel & 0x7);
APB_SARADC.thres1_ctrl.thres1_high = cfg->h_threshold;
APB_SARADC.thres1_ctrl.thres1_low = cfg->l_threshold;
}
}
/**
* Enable/disable monitor of adc digital controller.
*
* @note If the channel info is not supported, the monitor function will not be enabled.
* @param adc_n ADC unit.
*/
static inline void adc_ll_digi_monitor_disable(adc_digi_monitor_idx_t idx)
{
if (idx == ADC_DIGI_MONITOR_IDX0) {
APB_SARADC.thres0_ctrl.thres0_channel = 0xF;
} else { // ADC_DIGI_MONITOR_IDX1
APB_SARADC.thres1_ctrl.thres1_channel = 0xF;
}
}
/**
* Set DMA eof num of adc digital controller.
* If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated.
*
* @param num eof num of DMA.
*/
static inline void adc_ll_digi_dma_set_eof_num(uint32_t num)
{
APB_SARADC.dma_conf.apb_adc_eof_num = num;
}
/**
* Enable output data to DMA from adc digital controller.
*/
static inline void adc_ll_digi_dma_enable(void)
{
APB_SARADC.dma_conf.apb_adc_trans = 1;
}
/**
* Disable output data to DMA from adc digital controller.
*/
static inline void adc_ll_digi_dma_disable(void)
{
APB_SARADC.dma_conf.apb_adc_trans = 0;
}
/**
* Reset adc digital controller.
*/
static inline void adc_ll_digi_reset(void)
{
APB_SARADC.dma_conf.apb_adc_reset_fsm = 1;
APB_SARADC.dma_conf.apb_adc_reset_fsm = 0;
}
/*---------------------------------------------------------------
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. */
RTCCNTL.sensor_ctrl.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 RTCCNTL.sensor_ctrl.sar2_pwdet_cct;
}
/**
* Analyze whether the obtained raw data is correct.
* ADC2 can use arbiter. The arbitration result is stored in the channel information of the returned data.
*
* @param adc_n ADC unit.
* @param raw_data ADC raw data input (convert value).
* @return
* - 0: The data is correct to use.
* - -1: The data is invalid.
*/
static inline adc_ll_rtc_raw_data_t adc_ll_analysis_raw_data(adc_ll_num_t adc_n, int raw_data)
{
if (adc_n == ADC_NUM_1) {
return ADC_RTC_DATA_OK;
}
//The raw data API returns value without channel information. Read value directly from the register
if (((APB_SARADC.apb_saradc2_data_status.adc2_data >> 13) & 0xF) > 9) {
return ADC_RTC_DATA_FAIL;
}
return ADC_RTC_DATA_OK;
}
/*---------------------------------------------------------------
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) {
APB_SARADC.ctrl.sar_clk_gated = 1;
APB_SARADC.ctrl.xpd_sar_force = 3;
} else if (manage == ADC_POWER_BY_FSM) {
APB_SARADC.ctrl.sar_clk_gated = 1;
APB_SARADC.ctrl.xpd_sar_force = 0;
} else if (manage == ADC_POWER_SW_OFF) {
APB_SARADC.ctrl.xpd_sar_force = 2;
APB_SARADC.ctrl.sar_clk_gated = 0;
}
}
/**
* Get ADC module power management.
*
* @return
* - ADC power status.
*/
static inline adc_ll_power_t adc_ll_get_power_manage(void)
{
/* Bit1 0:Fsm 1: SW mode
Bit0 0:SW mode power down 1: SW mode power on */
adc_ll_power_t manage;
if (APB_SARADC.ctrl.xpd_sar_force == 3) {
manage = ADC_POWER_SW_ON;
} else if (APB_SARADC.ctrl.xpd_sar_force == 2) {
manage = ADC_POWER_SW_OFF;
} else {
manage = ADC_POWER_BY_FSM;
}
return manage;
}
/**
* Set ADC2 module arbiter work mode.
* 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 ADC 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.
*
* @param mode Refer to `adc_arbiter_mode_t`.
*/
static inline void adc_ll_set_arbiter_work_mode(adc_arbiter_mode_t mode)
{
if (mode == ADC_ARB_MODE_FIX) {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_fix_priority = 1;
} else if (mode == ADC_ARB_MODE_LOOP) {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_fix_priority = 0;
} else {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_grant_force = 1; // Shield arbiter.
}
}
/**
* Set ADC2 module controller priority in 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 ADC 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(2) > RTC(1) > Digital(0);
*
* @param pri_rtc RTC controller priority. Range: 0 ~ 2.
* @param pri_dig Digital controller priority. Range: 0 ~ 2.
* @param pri_pwdet Wi-Fi controller priority. Range: 0 ~ 2.
*/
static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, uint8_t pri_pwdet)
{
if (pri_rtc != pri_dig && pri_rtc != pri_pwdet && pri_dig != pri_pwdet) {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_priority = pri_rtc;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_priority = pri_dig;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_priority = pri_pwdet;
}
/* Should select highest priority controller. */
if (pri_rtc > pri_dig) {
if (pri_rtc > pri_pwdet) {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 1;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 0;
} else {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 1;
}
} else {
if (pri_dig > pri_pwdet) {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 1;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 0;
} else {
APB_SARADC.apb_adc_arb_ctrl.adc_arb_apb_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_rtc_force = 0;
APB_SARADC.apb_adc_arb_ctrl.adc_arb_wifi_force = 1;
}
}
}
/* ADC calibration code. */
/**
* @brief Set common calibration configuration. Should be shared with other parts (PWDET).
*/
static inline void adc_ll_calibration_init(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 1);
}
}
/**
* Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration.
*
* @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 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.
*/
static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t channel, bool internal_gnd)
{
/* Enable/disable internal connect GND (for calibration). */
if (adc_n == ADC_NUM_1) {
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
}
} else {
if (internal_gnd) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0);
}
}
}
/**
* Resume register status after calibration.
*
* @param adc_n ADC index number.
*/
static inline void adc_ll_calibration_finish(adc_ll_num_t adc_n)
{
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0);
}
}
/**
* Set the calibration result to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
*/
static inline void adc_ll_set_calibration_param(adc_ll_num_t adc_n, uint32_t param)
{
uint8_t msb = param >> 8;
uint8_t lsb = param & 0xFF;
if (adc_n == ADC_NUM_1) {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, msb);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, lsb);
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_HIGH_ADDR, msb);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, lsb);
}
}
/* Temp code end. */
/**
* Output ADCn inter reference voltage to ADC2 channels.
*
* This function routes the internal reference voltage of ADCn to one of
* ADC1's channels. This reference voltage can then be manually measured
* for calibration purposes.
*
* @param[in] adc ADC unit select
* @param[in] channel ADC1 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 (en) {
REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 3);
SET_PERI_REG_MASK(RTC_CNTL_REG, RTC_CNTL_REGULATOR_FORCE_PU);
REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_SEL, 2);
SET_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN);
SET_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_GRANT_FORCE);
SET_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_APB_FORCE);
APB_SARADC.sar_patt_tab[0].sar_patt_tab1 = 0xFFFFFF;
APB_SARADC.sar_patt_tab[1].sar_patt_tab1 = 0xFFFFFF;
APB_SARADC.onetime_sample.adc1_onetime_sample = 1;
APB_SARADC.onetime_sample.onetime_channel = channel;
SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU);
if (adc == ADC_NUM_1) {
/* Config test mux to route v_ref to ADC1 Channels */
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 1);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 1);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_TSENS_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 1);
} else {
/* Config test mux to route v_ref to ADC2 Channels */
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 1);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_TSENS_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0);
}
} else {
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_DTEST_RTC_ADDR, 0);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC_ENT_RTC_ADDR, 0);
APB_SARADC.onetime_sample.adc1_onetime_sample = 0;
APB_SARADC.onetime_sample.onetime_channel = 0xf;
REG_SET_FIELD(RTC_CNTL_SENSOR_CTRL_REG, RTC_CNTL_FORCE_XPD_SAR, 0);
REG_SET_FIELD(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_SEL, 0);
CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_CLKM_CONF_REG, APB_SARADC_CLK_EN);
CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_GRANT_FORCE);
CLEAR_PERI_REG_MASK(APB_SARADC_APB_ADC_ARB_CTRL_REG, APB_SARADC_ADC_ARB_APB_FORCE);
}
}
/*---------------------------------------------------------------
Single Read
---------------------------------------------------------------*/
/**
* Trigger single read
*
* @param val Usage: set to 1 to start the ADC conversion. The step signal should at least keep 3 ADC digital controller clock cycle,
* otherwise the step signal may not be captured by the ADC digital controller when its frequency is slow.
* This hardware limitation will be removed in future versions.
*/
static inline void adc_ll_onetime_start(bool val)
{
APB_SARADC.onetime_sample.onetime_start = val;
}
static inline void adc_ll_onetime_set_channel(adc_ll_num_t unit, adc_channel_t channel)
{
APB_SARADC.onetime_sample.onetime_channel = ((unit << 3) | channel);
}
static inline void adc_ll_onetime_set_atten(adc_atten_t atten)
{
APB_SARADC.onetime_sample.onetime_atten = atten;
}
static inline void adc_ll_intr_enable(adc_ll_intr_t mask)
{
APB_SARADC.int_ena.val |= mask;
}
static inline void adc_ll_intr_disable(adc_ll_intr_t mask)
{
APB_SARADC.int_ena.val &= ~mask;
}
static inline void adc_ll_intr_clear(adc_ll_intr_t mask)
{
APB_SARADC.int_clr.val |= mask;
}
static inline bool adc_ll_intr_get_raw(adc_ll_intr_t mask)
{
return (APB_SARADC.int_raw.val & mask);
}
static inline bool adc_ll_intr_get_status(adc_ll_intr_t mask)
{
return (APB_SARADC.int_st.val & mask);
}
static inline void adc_ll_onetime_sample_enable(adc_ll_num_t adc_n, bool enable)
{
if (adc_n == ADC_NUM_1) {
APB_SARADC.onetime_sample.adc1_onetime_sample = enable;
} else {
APB_SARADC.onetime_sample.adc2_onetime_sample = enable;
}
}
static inline uint32_t adc_ll_adc1_read(void)
{
//On ESP32C3, valid data width is 12-bit
return (APB_SARADC.apb_saradc1_data_status.adc1_data & 0xfff);
}
static inline uint32_t adc_ll_adc2_read(void)
{
//On ESP32C3, valid data width is 12-bit
return (APB_SARADC.apb_saradc2_data_status.adc2_data & 0xfff);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,235 @@
// 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 "soc/hwcrypto_reg.h"
#include "hal/aes_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief State of AES accelerator, busy, idle or done
*
*/
typedef enum {
ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */
ESP_AES_STATE_BUSY, /* Transform in progress */
ESP_AES_STATE_DONE, /* Transform completed */
} 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 volatile number of bytes written to hardware, used for fault injection check
*/
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_in_hardware = 0;
uint32_t *key_words = (uint32_t *)key;
for (int i = 0; i < key_word_len; i++) {
REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i));
key_in_hardware += 4;
}
return key_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 */
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 void *input)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t i0, i1, i2, i3;
/* Storing i0,i1,i2,i3 in registers, not in an array
helps a lot with optimisations at -Os level */
i0 = input_words[0];
REG_WRITE(AES_TEXT_IN_BASE, i0);
i1 = input_words[1];
REG_WRITE(AES_TEXT_IN_BASE + 4, i1);
i2 = input_words[2];
REG_WRITE(AES_TEXT_IN_BASE + 8, i2);
i3 = input_words[3];
REG_WRITE(AES_TEXT_IN_BASE + 12, i3);
}
/**
* @brief Read the AES block
*
* @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;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < AES_BLOCK_WORDS; i++) {
output_words[i] = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Starts block transform
*
*/
static inline void aes_ll_start_transform(void)
{
REG_WRITE(AES_TRIGGER_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 REG_READ(AES_STATE_REG);
}
/**
* @brief Set mode of operation
*
* @note Only used for DMA transforms
*
* @param mode
*/
static inline void aes_ll_set_block_mode(esp_aes_mode_t mode)
{
REG_WRITE(AES_BLOCK_MODE_REG, mode);
}
/**
* @brief Set AES-CTR counter to INC32
*
* @note Only affects AES-CTR mode
*
*/
static inline void aes_ll_set_inc(void)
{
REG_WRITE(AES_INC_SEL_REG, 0);
}
/**
* @brief Release the DMA
*
*/
static inline void aes_ll_dma_exit(void)
{
REG_WRITE(AES_DMA_EXIT_REG, 0);
}
/**
* @brief Sets the number of blocks to be transformed
*
* @note Only used for DMA transforms
*
* @param num_blocks Number of blocks to transform
*/
static inline void aes_ll_set_num_blocks(size_t num_blocks)
{
REG_WRITE(AES_BLOCK_NUM_REG, num_blocks);
}
/*
* Write IV to hardware iv registers
*/
static inline void aes_ll_set_iv(const uint8_t *iv)
{
uint32_t *iv_words = (uint32_t *)iv;
uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE);
for (int i = 0; i < IV_WORDS; i++ ) {
REG_WRITE(&reg_addr_buf[i], iv_words[i]);
}
}
/*
* Read IV from hardware iv registers
*/
static inline void aes_ll_read_iv(uint8_t *iv)
{
uint32_t *iv_words = (uint32_t *)iv;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < IV_WORDS; i++) {
iv_words[i] = REG_READ(AES_IV_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Enable or disable DMA mode
*
* @param enable true to enable, false to disable.
*/
static inline void aes_ll_dma_enable(bool enable)
{
REG_WRITE(AES_DMA_ENABLE_REG, enable);
}
/**
* @brief Enable or disable transform completed interrupt
*
* @param enable true to enable, false to disable.
*/
static inline void aes_ll_interrupt_enable(bool enable)
{
REG_WRITE(AES_INT_ENA_REG, enable);
}
/**
* @brief Clears the interrupt
*
*/
static inline void aes_ll_interrupt_clear(void)
{
REG_WRITE(AES_INT_CLR_REG, 1);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,252 @@
// 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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/periph_defs.h"
#include "soc/system_reg.h"
#include "soc/syscon_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_SARADC_MODULE:
return SYSTEM_APB_SARADC_CLK_EN;
case PERIPH_RMT_MODULE:
return SYSTEM_RMT_CLK_EN;
case PERIPH_LEDC_MODULE:
return SYSTEM_LEDC_CLK_EN;
case PERIPH_UART0_MODULE:
return SYSTEM_UART_CLK_EN;
case PERIPH_UART1_MODULE:
return SYSTEM_UART1_CLK_EN;
case PERIPH_I2C0_MODULE:
return SYSTEM_I2C_EXT0_CLK_EN;
case PERIPH_I2S1_MODULE:
return SYSTEM_I2S1_CLK_EN;
case PERIPH_TIMG0_MODULE:
return SYSTEM_TIMERGROUP_CLK_EN;
case PERIPH_TIMG1_MODULE:
return SYSTEM_TIMERGROUP1_CLK_EN;
case PERIPH_UHCI0_MODULE:
return SYSTEM_UHCI0_CLK_EN;
case PERIPH_SYSTIMER_MODULE:
return SYSTEM_SYSTIMER_CLK_EN;
case PERIPH_SPI_MODULE:
return SYSTEM_SPI01_CLK_EN;
case PERIPH_SPI2_MODULE:
return SYSTEM_SPI2_CLK_EN;
case PERIPH_TWAI_MODULE:
return SYSTEM_TWAI_CLK_EN;
case PERIPH_GDMA_MODULE:
return SYSTEM_DMA_CLK_EN;
case PERIPH_AES_MODULE:
return SYSTEM_CRYPTO_AES_CLK_EN;
case PERIPH_SHA_MODULE:
return SYSTEM_CRYPTO_SHA_CLK_EN;
case PERIPH_RSA_MODULE:
return SYSTEM_CRYPTO_RSA_CLK_EN;
case PERIPH_HMAC_MODULE:
return SYSTEM_CRYPTO_HMAC_CLK_EN;
case PERIPH_DS_MODULE:
return SYSTEM_CRYPTO_DS_CLK_EN;
case PERIPH_RNG_MODULE:
return SYSTEM_WIFI_CLK_RNG_EN;
case PERIPH_WIFI_MODULE:
return SYSTEM_WIFI_CLK_WIFI_EN_M;
case PERIPH_BT_MODULE:
return SYSTEM_WIFI_CLK_BT_EN_M;
case PERIPH_WIFI_BT_COMMON_MODULE:
return SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M;
case PERIPH_BT_BASEBAND_MODULE:
return SYSTEM_BT_BASEBAND_EN;
case PERIPH_BT_LC_MODULE:
return SYSTEM_BT_LC_EN;
default:
return 0;
}
}
static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable)
{
(void)enable; // unused
switch (periph) {
case PERIPH_SARADC_MODULE:
return SYSTEM_APB_SARADC_RST;
case PERIPH_RMT_MODULE:
return SYSTEM_RMT_RST;
case PERIPH_LEDC_MODULE:
return SYSTEM_LEDC_RST;
case PERIPH_UART0_MODULE:
return SYSTEM_UART_RST;
case PERIPH_UART1_MODULE:
return SYSTEM_UART1_RST;
case PERIPH_I2C0_MODULE:
return SYSTEM_I2C_EXT0_RST;
case PERIPH_I2S1_MODULE:
return SYSTEM_I2S1_RST;
case PERIPH_TIMG0_MODULE:
return SYSTEM_TIMERGROUP_RST;
case PERIPH_TIMG1_MODULE:
return SYSTEM_TIMERGROUP1_RST;
case PERIPH_UHCI0_MODULE:
return SYSTEM_UHCI0_RST;
case PERIPH_SYSTIMER_MODULE:
return SYSTEM_SYSTIMER_RST;
case PERIPH_GDMA_MODULE:
return SYSTEM_DMA_RST;
case PERIPH_SPI_MODULE:
return SYSTEM_SPI01_RST;
case PERIPH_SPI2_MODULE:
return SYSTEM_SPI2_RST;
case PERIPH_TWAI_MODULE:
return SYSTEM_TWAI_RST;
case PERIPH_HMAC_MODULE:
return SYSTEM_CRYPTO_HMAC_RST;
case PERIPH_AES_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise AES unit is held in reset also.
return (SYSTEM_CRYPTO_AES_RST | SYSTEM_CRYPTO_DS_RST);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return SYSTEM_CRYPTO_AES_RST;
}
case PERIPH_SHA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
return (SYSTEM_CRYPTO_SHA_RST | SYSTEM_CRYPTO_DS_RST | SYSTEM_CRYPTO_HMAC_RST);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return SYSTEM_CRYPTO_SHA_RST;
}
case PERIPH_RSA_MODULE:
if (enable == true) {
/* also clear reset on digital signature, otherwise RSA is held in reset */
return (SYSTEM_CRYPTO_RSA_RST | SYSTEM_CRYPTO_DS_RST);
} else {
/* don't reset digital signature unit, as this resets AES also */
return SYSTEM_CRYPTO_RSA_RST;
}
case PERIPH_DS_MODULE:
return SYSTEM_CRYPTO_DS_RST;
default:
return 0;
}
}
static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
{
switch (periph) {
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 SYSTEM_WIFI_CLK_EN_REG;
case PERIPH_HMAC_MODULE:
case PERIPH_DS_MODULE:
case PERIPH_AES_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_GDMA_MODULE:
return SYSTEM_PERIP_CLK_EN1_REG;
default:
return SYSTEM_PERIP_CLK_EN0_REG;
}
}
static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
{
switch (periph) {
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 SYSTEM_WIFI_RST_EN_REG;
case PERIPH_HMAC_MODULE:
case PERIPH_DS_MODULE:
case PERIPH_AES_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_GDMA_MODULE:
return SYSTEM_PERIP_RST_EN1_REG;
default:
return SYSTEM_PERIP_RST_EN0_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(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_CLEAR_PERI_REG_MASK(SYSTEM_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(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_SET_PERI_REG_MASK(SYSTEM_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(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
DPORT_CLEAR_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
}
static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
{
DPORT_CLEAR_PERI_REG_MASK(SYSTEM_WIFI_CLK_EN_REG, SYSTEM_WIFI_CLK_WIFI_EN_M);
DPORT_SET_PERI_REG_MASK(SYSTEM_CORE_RST_EN_REG, 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,161 @@
// 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/cpu_caps.h"
#include "esp_bit_defs.h"
#include "soc/assist_debug_reg.h"
#include "esp_attr.h"
#include "riscv/csr.h"
/*performance counter*/
#define CSR_PCER_MACHINE 0x7e0
#define CSR_PCMR_MACHINE 0x7e1
#define CSR_PCCR_MACHINE 0x7e2
#ifdef __cplusplus
extern "C" {
#endif
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
{
#if SOC_CPU_CORES_NUM == 1
return 0; // No need to check core ID on single core hardware
#else
int cpuid;
cpuid = RV_READ_CSR(mhartid);
return cpuid;
#endif
}
static inline void cpu_ll_enable_cycle_count(void)
{
RV_WRITE_CSR(CSR_PCER_MACHINE,1);
RV_WRITE_CSR(CSR_PCMR_MACHINE,1);
return;
}
static inline uint32_t IRAM_ATTR cpu_ll_get_cycle_count(void)
{
uint32_t result;
result = RV_READ_CSR(CSR_PCCR_MACHINE);
return result;
}
static inline void IRAM_ATTR cpu_ll_set_cycle_count(uint32_t val)
{
RV_WRITE_CSR(CSR_PCCR_MACHINE, val);
}
static inline void* cpu_ll_get_sp(void)
{
void *sp;
asm volatile ("mv %0, sp;" : "=r" (sp));
return sp;
}
static inline void cpu_ll_init_hwloop(void)
{
// Nothing needed here for ESP32-C3
}
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
{
RV_WRITE_CSR(tselect,id);
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
RV_WRITE_CSR(tdata2,pc);
return;
}
static inline void cpu_ll_clear_breakpoint(int id)
{
RV_WRITE_CSR(tselect,id);
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
return;
}
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 & 0x3fffffff) | 0x40000000);
}
static inline void cpu_ll_set_watchpoint(int id,
const void* addr,
size_t size,
bool on_read,
bool on_write)
{
uint32_t addr_napot;
RV_WRITE_CSR(tselect,id);
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
RV_SET_CSR_FIELD(CSR_TDATA1, TDATA1_MATCH, 1);
// add 0 in napot encoding
addr_napot = ((uint32_t) addr) | ((size >> 1) - 1);
if (on_read) {
RV_SET_CSR(CSR_TDATA1, TDATA1_LOAD);
}
if (on_write) {
RV_SET_CSR(CSR_TDATA1, TDATA1_STORE);
}
RV_WRITE_CSR(tdata2,addr_napot);
return;
}
static inline void cpu_ll_clear_watchpoint(int id)
{
RV_WRITE_CSR(tselect,id);
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
RV_CLEAR_CSR_FIELD(CSR_TDATA1,TDATA1_MATCH);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_MACHINE);
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_LOAD|TDATA1_STORE|TDATA1_EXECUTE);
return;
}
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
{
return REG_GET_BIT(ASSIST_DEBUG_C0RE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
}
static inline void cpu_ll_break(void)
{
asm volatile("ebreak\n");
return;
}
static inline void cpu_ll_set_vecbase(const void* vecbase)
{
uintptr_t vecbase_int = (uintptr_t)vecbase;
vecbase_int |= 1; // Set MODE field to treat MTVEC as a vector base address
RV_WRITE_CSR(mtvec, vecbase_int);
}
static inline void cpu_ll_waiti(void)
{
asm volatile ("wfi\n");
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,175 @@
// 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.
******************************************************************************/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "soc/hwcrypto_reg.h"
#include "soc/ds_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void ds_ll_start(void)
{
REG_WRITE(DS_SET_START_REG, 1);
}
/**
* @brief Wait until DS peripheral has finished any outstanding operation.
*/
static inline bool ds_ll_busy(void)
{
return (REG_READ(DS_QUERY_BUSY_REG) > 0) ? true : false;
}
/**
* @brief Busy wait until the hardware is ready.
*/
static inline void ds_ll_wait_busy(void)
{
while (ds_ll_busy());
}
/**
* @brief In case of a key error, check what caused it.
*/
static inline ds_key_check_t ds_ll_key_error_source(void)
{
uint32_t key_error = REG_READ(DS_QUERY_KEY_WRONG_REG);
if (key_error == 0) {
return DS_NO_KEY_INPUT;
} else {
return DS_OTHER_WRONG;
}
}
/**
* @brief Write the initialization vector to the corresponding register field.
*/
static inline void ds_ll_configure_iv(const uint32_t *iv)
{
for (size_t i = 0; i < (DS_KEY_PARAM_MD_IV_LENGTH / sizeof(uint32_t)); i++) {
REG_WRITE(DS_IV_BASE + (i * 4) , iv[i]);
}
}
/**
* @brief Write the message which should be signed.
*
* @param msg Pointer to the message.
* @param size Length of msg in bytes. It is the RSA signature length in bytes.
*/
static inline void ds_ll_write_message(const uint8_t *msg, size_t size)
{
memcpy((uint8_t*) DS_X_BASE, msg, size);
asm volatile ("fence");
}
/**
* @brief Write the encrypted private key parameters.
*/
static inline void ds_ll_write_private_key_params(const uint8_t *encrypted_key_params)
{
/* Note: as the internal peripheral still has RSA 4096 structure,
but C is encrypted based on the actual max RSA length (ETS_DS_MAX_BITS), need to fragment it
when copying to hardware...
(note if ETS_DS_MAX_BITS == 4096, this should be the same as copying data->c to hardware in one fragment)
*/
typedef struct { uint32_t addr; size_t len; } frag_t;
const frag_t frags[] = {
{DS_C_Y_BASE, DS_SIGNATURE_MAX_BIT_LEN / 8},
{DS_C_M_BASE, DS_SIGNATURE_MAX_BIT_LEN / 8},
{DS_C_RB_BASE, DS_SIGNATURE_MAX_BIT_LEN / 8},
{DS_C_BOX_BASE, DS_IV_BASE - DS_C_BOX_BASE},
};
const size_t NUM_FRAGS = sizeof(frags)/sizeof(frag_t);
const uint8_t *from = encrypted_key_params;
for (int i = 0; i < NUM_FRAGS; i++) {
memcpy((uint8_t *)frags[i].addr, from, frags[i].len);
asm volatile ("fence");
from += frags[i].len;
}
}
/**
* @brief Begin signing procedure.
*/
static inline void ds_ll_start_sign(void)
{
REG_WRITE(DS_SET_ME_REG, 1);
}
/**
* @brief check the calculated signature.
*
* @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.
*/
static inline ds_signature_check_t ds_ll_check_signature(void)
{
uint32_t result = REG_READ(DS_QUERY_CHECK_REG);
switch(result) {
case 0:
return DS_SIGNATURE_OK;
case 1:
return DS_SIGNATURE_MD_FAIL;
case 2:
return DS_SIGNATURE_PADDING_FAIL;
default:
return DS_SIGNATURE_PADDING_AND_MD_FAIL;
}
}
/**
* @brief Read the signature from the hardware.
*
* @param result The signature result.
* @param size Length of signature result in bytes. It is the RSA signature length in bytes.
*/
static inline void ds_ll_read_result(uint8_t *result, size_t size)
{
memcpy(result, (uint8_t*) DS_Z_BASE, size);
asm volatile ("fence");
}
/**
* @brief Exit the signature operation.
*
* @note This does not deactivate the module. Corresponding clock/reset bits have to be triggered for deactivation.
*/
static inline void ds_ll_finish(void)
{
REG_WRITE(DS_SET_FINISH_REG, 1);
ds_ll_wait_busy();
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,410 @@
// 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/gdma_struct.h"
#include "soc/gdma_reg.h"
#include "soc/gdma_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GDMA_LL_GET_HW(id) (((id) == 0) ? (&GDMA) : NULL)
#define GDMA_LL_EVENT_TX_FIFO_UDF (1<<12)
#define GDMA_LL_EVENT_TX_FIFO_OVF (1<<11)
#define GDMA_LL_EVENT_RX_FIFO_UDF (1<<10)
#define GDMA_LL_EVENT_RX_FIFO_OVF (1<<9)
#define GDMA_LL_EVENT_TX_TOTAL_EOF (1<<8)
#define GDMA_LL_EVENT_RX_DESC_EMPTY (1<<7)
#define GDMA_LL_EVENT_TX_DESC_ERROR (1<<6)
#define GDMA_LL_EVENT_RX_DESC_ERROR (1<<5)
#define GDMA_LL_EVENT_TX_EOF (1<<4)
#define GDMA_LL_EVENT_TX_DONE (1<<3)
#define GDMA_LL_EVENT_RX_ERR_EOF (1<<2)
#define GDMA_LL_EVENT_RX_SUC_EOF (1<<1)
#define GDMA_LL_EVENT_RX_DONE (1<<0)
///////////////////////////////////// Common /////////////////////////////////////////
/**
* @brief Enable DMA channel M2M mode (TX channel n forward data to RX channel n), disabled by default
*/
static inline void gdma_ll_enable_m2m_mode(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].in.in_conf0.mem_trans_en = enable;
if (enable) {
// only have to give it a valid value
dev->channel[channel].in.in_peri_sel.sel = 0;
dev->channel[channel].out.out_peri_sel.sel = 0;
}
}
/**
* @brief Get DMA interrupt status word
*/
static inline uint32_t gdma_ll_get_interrupt_status(gdma_dev_t *dev, uint32_t channel)
{
return dev->intr[channel].st.val;
}
/**
* @brief Enable DMA interrupt
*/
static inline void gdma_ll_enable_interrupt(gdma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable)
{
if (enable) {
dev->intr[channel].ena.val |= mask;
} else {
dev->intr[channel].ena.val &= ~mask;
}
}
/**
* @brief Clear DMA interrupt
*/
static inline void gdma_ll_clear_interrupt_status(gdma_dev_t *dev, uint32_t channel, uint32_t mask)
{
dev->intr[channel].clr.val = mask;
}
/**
* @brief Enable DMA clock gating
*/
static inline void gdma_ll_enable_clock(gdma_dev_t *dev, bool enable)
{
dev->misc_conf.clk_en = enable;
}
///////////////////////////////////// RX /////////////////////////////////////////
/**
* @brief Enable DMA RX channel to check the owner bit in the descriptor, disabled by default
*/
static inline void gdma_ll_rx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].in.in_conf1.in_check_owner = enable;
}
/**
* @brief Enable DMA RX channel burst reading data, disabled by default
*/
static inline void gdma_ll_rx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].in.in_conf0.in_data_burst_en = enable;
}
/**
* @brief Enable DMA RX channel burst reading descriptor link, disabled by default
*/
static inline void gdma_ll_rx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].in.in_conf0.indscr_burst_en = enable;
}
/**
* @brief Reset DMA RX channel FSM and FIFO pointer
*/
static inline void gdma_ll_rx_reset_channel(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].in.in_conf0.in_rst = 1;
dev->channel[channel].in.in_conf0.in_rst = 0;
}
/**
* @brief Check if DMA RX FIFO is full
* @param fifo_level only supports level 1
*/
static inline bool gdma_ll_rx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].in.infifo_status.val & 0x01;
}
/**
* @brief Check if DMA RX FIFO is empty
* @param fifo_level only supports level 1
*/
static inline bool gdma_ll_rx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].in.infifo_status.val & 0x02;
}
/**
* @brief Get number of bytes in RX FIFO
* @param fifo_level only supports level 1
*/
static inline uint32_t gdma_ll_rx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].in.infifo_status.infifo_cnt;
}
/**
* @brief Pop data from DMA RX FIFO
*/
static inline uint32_t gdma_ll_rx_pop_data(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].in.in_pop.infifo_pop = 1;
return dev->channel[channel].in.in_pop.infifo_rdata;
}
/**
* @brief Set the descriptor link base address for RX channel
*/
static inline void gdma_ll_rx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr)
{
dev->channel[channel].in.in_link.addr = addr;
}
/**
* @brief Start dealing with RX descriptors
*/
static inline void gdma_ll_rx_start(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].in.in_link.start = 1;
}
/**
* @brief Stop dealing with RX descriptors
*/
static inline void gdma_ll_rx_stop(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].in.in_link.stop = 1;
}
/**
* @brief Restart a new inlink right after the last descriptor
*/
static inline void gdma_ll_rx_restart(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].in.in_link.restart = 1;
}
/**
* @brief Enable DMA RX to return the address of current descriptor when receives error
*/
static inline void gdma_ll_rx_enable_auto_return(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].in.in_link.auto_ret = enable;
}
/**
* @brief Check if DMA RX FSM is in IDLE state
*/
static inline bool gdma_ll_rx_is_fsm_idle(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].in.in_link.park;
}
/**
* @brief Get RX success EOF descriptor's address
*/
static inline uint32_t gdma_ll_rx_get_success_eof_desc_addr(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].in.in_suc_eof_des_addr;
}
/**
* @brief Get RX error EOF descriptor's address
*/
static inline uint32_t gdma_ll_rx_get_error_eof_desc_addr(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].in.in_err_eof_des_addr;
}
/**
* @brief Get current RX descriptor's address
*/
static inline uint32_t gdma_ll_rx_get_current_desc_addr(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].in.in_dscr;
}
/**
* @brief Set priority for DMA RX channel
*/
static inline void gdma_ll_rx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio)
{
dev->channel[channel].in.in_pri.rx_pri = prio;
}
/**
* @brief Connect DMA RX channel to a given peripheral
*/
static inline void gdma_ll_rx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, int periph_id)
{
dev->channel[channel].in.in_peri_sel.sel = periph_id;
}
///////////////////////////////////// TX /////////////////////////////////////////
/**
* @brief Enable DMA TX channel to check the owner bit in the descriptor, disabled by default
*/
static inline void gdma_ll_tx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].out.out_conf1.out_check_owner = enable;
}
/**
* @brief Enable DMA TX channel burst sending data, disabled by default
*/
static inline void gdma_ll_tx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].out.out_conf0.out_data_burst_en = enable;
}
/**
* @brief Enable DMA TX channel burst reading descriptor link, disabled by default
*/
static inline void gdma_ll_tx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].out.out_conf0.outdscr_burst_en = enable;
}
/**
* @brief Set TX channel EOF mode
*/
static inline void gdma_ll_tx_set_eof_mode(gdma_dev_t *dev, uint32_t channel, uint32_t mode)
{
dev->channel[channel].out.out_conf0.out_eof_mode = mode;
}
/**
* @brief Enable DMA TX channel automatic write results back to descriptor after all data has been sent out, disabled by default
*/
static inline void gdma_ll_tx_enable_auto_write_back(gdma_dev_t *dev, uint32_t channel, bool enable)
{
dev->channel[channel].out.out_conf0.out_auto_wrback = enable;
}
/**
* @brief Reset DMA TX channel FSM and FIFO pointer
*/
static inline void gdma_ll_tx_reset_channel(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].out.out_conf0.out_rst = 1;
dev->channel[channel].out.out_conf0.out_rst = 0;
}
/**
* @brief Check if DMA TX FIFO is full
* @param fifo_level only supports level 1
*/
static inline bool gdma_ll_tx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].out.outfifo_status.val & 0x01;
}
/**
* @brief Check if DMA TX FIFO is empty
* @param fifo_level only supports level 1
*/
static inline bool gdma_ll_tx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].out.outfifo_status.val & 0x02;
}
/**
* @brief Get number of bytes in TX FIFO
* @param fifo_level only supports level 1
*/
static inline uint32_t gdma_ll_tx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level)
{
return dev->channel[channel].out.outfifo_status.outfifo_cnt;
}
/**
* @brief Push data into DMA TX FIFO
*/
static inline void gdma_ll_tx_push_data(gdma_dev_t *dev, uint32_t channel, uint32_t data)
{
dev->channel[channel].out.out_push.outfifo_wdata = data;
dev->channel[channel].out.out_push.outfifo_push = 1;
}
/**
* @brief Set the descriptor link base address for TX channel
*/
static inline void gdma_ll_tx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr)
{
dev->channel[channel].out.out_link.addr = addr;
}
/**
* @brief Start dealing with TX descriptors
*/
static inline void gdma_ll_tx_start(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].out.out_link.start = 1;
}
/**
* @brief Stop dealing with TX descriptors
*/
static inline void gdma_ll_tx_stop(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].out.out_link.stop = 1;
}
/**
* @brief Restart a new outlink right after the last descriptor
*/
static inline void gdma_ll_tx_restart(gdma_dev_t *dev, uint32_t channel)
{
dev->channel[channel].out.out_link.restart = 1;
}
/**
* @brief Check if DMA TX FSM is in IDLE state
*/
static inline bool gdma_ll_tx_is_fsm_idle(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].out.out_link.park;
}
/**
* @brief Get TX EOF descriptor's address
*/
static inline uint32_t gdma_ll_tx_get_eof_desc_addr(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].out.out_eof_des_addr;
}
/**
* @brief Get current TX descriptor's address
*/
static inline uint32_t gdma_ll_tx_get_current_desc_addr(gdma_dev_t *dev, uint32_t channel)
{
return dev->channel[channel].out.out_dscr;
}
/**
* @brief Set priority for DMA TX channel
*/
static inline void gdma_ll_tx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio)
{
dev->channel[channel].out.out_pri.tx_pri = prio;
}
/**
* @brief Connect DMA TX channel to a given peripheral
*/
static inline void gdma_ll_tx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, int periph_id)
{
dev->channel[channel].out.out_peri_sel.sel = periph_id;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,561 @@
// 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
******************************************************************************/
// The LL layer for ESP32-C3 GPIO register operations
#pragma once
#include "soc/soc.h"
#include "soc/gpio_periph.h"
#include "soc/rtc_cntl_reg.h"
#include "hal/gpio_types.h"
#include "stdlib.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_PRO_CPU_INTR_ENA (BIT(0))
#define GPIO_LL_PRO_CPU_NMI_INTR_ENA (BIT(1))
/**
* @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 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 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 = hw->pcpu_int.intr;
}
/**
* @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 = 0; // Less than 32 GPIOs in ESP32-C3
}
/**
* @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.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)
{
// Not supported on C3
}
/**
* @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) {
GPIO.pin[gpio_num].int_ena = GPIO_LL_PRO_CPU_INTR_ENA; //enable pro cpu intr
} else {
// GPIO.pin[gpio_num].int_ena = GPIO_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)
{
hw->enable_w1tc.enable_w1tc = (0x1 << gpio_num);
// 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)
{
hw->enable_w1ts.enable_w1ts = (0x1 << 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) {
hw->out_w1ts.out_w1ts = (1 << gpio_num);
} else {
hw->out_w1tc.out_w1tc = (1 << gpio_num);
}
}
/**
* @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)
{
return (hw->in.data >> gpio_num) & 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 = 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)
{
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD);
}
/**
* @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)
{
if (gpio_num <= GPIO_NUM_5) {
REG_SET_BIT(RTC_CNTL_PAD_HOLD_REG, BIT(gpio_num));
} else {
SET_PERI_REG_MASK(RTC_CNTL_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)
{
if (gpio_num <= GPIO_NUM_5) {
REG_CLR_BIT(RTC_CNTL_PAD_HOLD_REG, BIT(gpio_num));
} else {
CLEAR_PERI_REG_MASK(RTC_CNTL_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 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;
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], func);
}
static inline void gpio_ll_force_hold_all(gpio_dev_t *hw)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_HOLD);
SET_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PAD_FORCE_HOLD_M);
}
static inline void gpio_ll_force_unhold_all(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_HOLD);
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PAD_FORCE_HOLD_M);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD);
}
/**
* @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 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 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 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 Enable GPIO deep-sleep 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_deepsleep_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
if (gpio_num > GPIO_NUM_5) {
abort(); // gpio lager than 5 doesn't support.
}
REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN_CLK_GATE);
REG_SET_BIT(RTC_CNTL_EXT_WAKEUP_CONF_REG, RTC_CNTL_GPIO_WAKEUP_FILTER);
SET_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, 1 << (RTC_CNTL_GPIO_PIN0_WAKEUP_ENABLE_S - gpio_num));
uint32_t reg = REG_READ(RTC_CNTL_GPIO_WAKEUP_REG);
reg &= (~(RTC_CNTL_GPIO_PIN0_INT_TYPE_V << (RTC_CNTL_GPIO_PIN0_INT_TYPE_S - gpio_num * 3)));
reg |= (intr_type << (RTC_CNTL_GPIO_PIN0_INT_TYPE_S - gpio_num * 3));
REG_WRITE(RTC_CNTL_GPIO_WAKEUP_REG, reg);
}
/**
* @brief Disable GPIO deep-sleep wake-up function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_deepsleep_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
if (gpio_num > GPIO_NUM_5) {
abort(); // gpio lager than 5 doesn't support.
}
CLEAR_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, 1 << (RTC_CNTL_GPIO_PIN0_WAKEUP_ENABLE_S - gpio_num));
CLEAR_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_PIN0_INT_TYPE_S - gpio_num * 3);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,388 @@
// 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 ll is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include <stdlib.h>
#include "soc/spi_periph.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>
#ifdef __cplusplus
extern "C" {
#endif
//NOTE: These macros are changed on c3 for build. MODIFY these when bringup flash.
#define gpspi_flash_ll_get_hw(host_id) ( ((host_id)==SPI2_HOST) ? &GPSPI2 : ({abort();(spi_dev_t*)0;}) )
#define gpspi_flash_ll_hw_get_id(dev) ( ((dev) == (void*)&GPSPI2) ? SPI2_HOST : -1 )
typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t;
//Supported clock register values
#define GPSPI_FLASH_LL_CLKREG_VAL_5MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_10MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_20MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_26MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_40MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_80MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/*------------------------------------------------------------------------------
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_reset(spi_dev_t *dev)
{
dev->user.val = 0;
dev->ctrl.val = 0;
dev->clk_gate.clk_en = 1;
dev->clk_gate.mst_clk_active = 1;
dev->clk_gate.mst_clk_sel = 1;
dev->dma_conf.val = 0;
dev->dma_conf.tx_seg_trans_clr_en = 1;
dev->dma_conf.rx_seg_trans_clr_en = 1;
dev->dma_conf.dma_seg_trans_en = 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 gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev)
{
return (dev->cmd.usr == 0);
}
/**
* Get the read data from the buffer after ``gpspi_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 gpspi_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 (int 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 gpspi_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 gpspi_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) / 4;
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);
}
}
/**
* 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 gpspi_flash_ll_user_start(spi_dev_t *dev)
{
dev->ctrl.hold_pol = 1;
dev->cmd.update = 1;
while (dev->cmd.update);
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 gpspi_flash_ll_host_idle(const spi_dev_t *dev)
{
return dev->cmd.usr == 0;
}
/**
* Set phases for user-defined transaction to read
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_read_phase(spi_dev_t *dev)
{
typeof (dev->user) user = {
.usr_command = 1,
.usr_mosi = 0,
.usr_miso = 1,
.usr_addr = 1,
};
dev->user = user;
}
/*------------------------------------------------------------------------------
* 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 gpspi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin)
{
dev->misc.cs0_dis = (pin == 0) ? 0 : 1;
dev->misc.cs1_dis = (pin == 1) ? 0 : 1;
}
/**
* 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 gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
typeof (dev->user) user = dev->user;
ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M);
user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M);
switch (read_mode) {
case SPI_FLASH_FASTRD:
//the default option
case SPI_FLASH_SLOWRD:
break;
case SPI_FLASH_QIO:
ctrl.fread_quad = 1;
ctrl.faddr_quad = 1;
user.fwrite_quad = 1;
break;
case SPI_FLASH_QOUT:
ctrl.fread_quad = 1;
user.fwrite_quad = 1;
break;
case SPI_FLASH_DIO:
ctrl.fread_dual = 1;
ctrl.faddr_dual = 1;
user.fwrite_dual = 1;
break;
case SPI_FLASH_DOUT:
ctrl.fread_dual = 1;
user.fwrite_dual = 1;
break;
default:
abort();
}
dev->ctrl = ctrl;
dev->user = user;
}
/**
* 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 gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_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 gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
}
/**
* 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 gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
if (bitlen) {
dev->ms_dlen.ms_data_bitlen = bitlen - 1;
}
}
/**
* 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 gpspi_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 gpspi_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 gpspi_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 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 gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
// The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | 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 gpspi_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 gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
{
dev->user.usr_dummy = dummy_n ? 1 : 0;
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
/**
* Set D/Q output level during dummy phase
*
* @param dev Beginning address of the peripheral registers.
* @param out_en whether to enable IO output for dummy phase
* @param out_level dummy output level
*/
static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev)
{
dev->ctrl.dummy_out = out_en;
dev->ctrl.q_pol = out_lev;
dev->ctrl.d_pol = out_lev;
}
/**
* Set extra hold time of CS after the clocks.
*
* @param dev Beginning address of the peripheral registers.
* @param hold_n Cycles of clocks before CS is inactive
*/
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->user1.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,109 @@
// 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
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The HMAC peripheral can be configured to deliver its output to the user directly, or to deliver
* the output directly to another peripheral instead, e.g. the Digital Signature peripheral.
*/
typedef enum {
HMAC_OUTPUT_USER = 0, /**< Let user provide a message and read the HMAC result */
HMAC_OUTPUT_DS = 1, /**< HMAC is provided to the DS peripheral to decrypt DS private key parameters */
HMAC_OUTPUT_JTAG_ENABLE = 2, /**< HMAC is used to enable JTAG after soft-disabling it */
HMAC_OUTPUT_ALL = 3 /**< HMAC is used for both as DS input for or enabling JTAG */
} hmac_hal_output_t;
/**
* @brief Make the peripheral ready for use.
*
* This triggers any further steps necessary after enabling the device
*/
void hmac_hal_start(void);
/**
* @brief Configure which hardware key slot should be used and configure the target of the HMAC output.
*
* @note Writing out-of-range values is undefined behavior. The user has to ensure that the parameters are in range.
*
* @param config The target of the HMAC. Possible targets are described in \c hmac_hal_output_t.
* See the ESP32C3 TRM for more details.
* @param key_id The ID of the hardware key slot to be used.
*
* @return 0 if the configuration was successful, non-zero if not.
* An unsuccessful configuration means that the purpose value in the eFuse of the corresponding key slot
* doesn't match to supplied value of \c config.
*/
uint32_t hmac_hal_configure(hmac_hal_output_t config, uint32_t key_id);
/**
* @brief Write a padded single-block message of 512 bits to the HMAC peripheral.
*
* The message must not be longer than one block (512 bits) and the padding has to be applied by software before
* writing. The padding has to be able to fit into the block after the message.
* For more information on HMAC padding, see the ESP32C3 TRM.
*/
void hmac_hal_write_one_block_512(const void *block);
/**
* @brief Write a message block of 512 bits to the HMAC peripheral.
*
* This function must be used incombination with \c hmac_hal_next_block_normal() or \c hmac_hal_next_block_padding().
* The first message block is written without any prerequisite.
* All message blocks which are not the last one, need a call to \c hmac_hal_next_block_normal() before, indicating
* to the hardware that a "normal", i.e. non-padded block will follow. This is even the case for a block which begins
* padding already but where the padding doesn't fit in (remaining message size > (block size - padding size)).
* Before writing the last block which contains the padding, a call to \c hmac_hal_next_block_padding() is necessary
* to indicate to the hardware that a block with padding will be written.
*
* For more information on HMAC padding, see the ESP32C3 TRM.
*/
void hmac_hal_write_block_512(const void *block);
/**
* @brief Indicate to the hardware that a normal block will be written.
*/
void hmac_hal_next_block_normal(void);
/**
* @brief Indicate to the hardware that a block with padding will be written.
*/
void hmac_hal_next_block_padding(void);
/**
* @brief Read the 256 bit HMAC result from the hardware.
*/
void hmac_hal_read_result_256(void *result);
/**
* @brief Clear (invalidate) the HMAC result provided to other hardware.
*/
void hmac_hal_clean(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,199 @@
// 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
#include <string.h>
#include "soc/system_reg.h"
#include "soc/hwcrypto_reg.h"
#include "hal/hmac_hal.h"
#define SHA256_BLOCK_SZ 64
#define SHA256_DIGEST_SZ 32
#define EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG 6
#define EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE 7
#define EFUSE_KEY_PURPOSE_HMAC_UP 8
#define EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL 5
#ifdef __cplusplus
extern "C" {
#endif
/**
* Makes the peripheral ready for use, after enabling it.
*/
static inline void hmac_ll_start(void)
{
REG_WRITE(HMAC_SET_START_REG, 1);
}
/**
* @brief Determine where the HMAC output should go.
*
* The HMAC peripheral can be configured to deliver its output to the user directly, or to deliver
* the output directly to another peripheral instead, e.g. the Digital Signature peripheral.
*/
static inline void hmac_ll_config_output(hmac_hal_output_t config)
{
switch(config) {
case HMAC_OUTPUT_USER:
REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, EFUSE_KEY_PURPOSE_HMAC_UP);
break;
case HMAC_OUTPUT_DS:
REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE);
break;
case HMAC_OUTPUT_JTAG_ENABLE:
REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG);
break;
case HMAC_OUTPUT_ALL:
REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL);
break;
default:
; // do nothing, error will be indicated by hmac_hal_config_error()
}
}
/**
* @brief Selects which hardware key should be used.
*/
static inline void hmac_ll_config_hw_key_id(uint32_t key_id)
{
REG_WRITE(HMAC_SET_PARA_KEY_REG, key_id);
}
/**
* @brief Apply and check configuration.
*
* Afterwards, the configuration can be checked for errors with hmac_hal_config_error().
*/
static inline void hmac_ll_config_finish(void)
{
REG_WRITE(HMAC_SET_PARA_FINISH_REG, 1);
}
/**
*
* @brief Query HMAC error state after configuration actions.
*
* @return
* - 1 or greater on error
* - 0 on success
*/
static inline uint32_t hmac_ll_config_error(void)
{
return REG_READ(HMAC_QUERY_ERROR_REG);
}
/**
* Wait until the HAL is ready for the next interaction.
*/
static inline void hmac_ll_wait_idle(void)
{
uint32_t query;
do {
query = REG_READ(HMAC_QUERY_BUSY_REG);
} while(query != 0);
}
/**
* @brief Write a message block of 512 bits to the HMAC peripheral.
*/
static inline void hmac_ll_write_block_512(const uint32_t *block)
{
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < SHA256_BLOCK_SZ / REG_WIDTH; i++) {
REG_WRITE(HMAC_WDATA_BASE + (i * REG_WIDTH), block[i]);
}
REG_WRITE(HMAC_SET_MESSAGE_ONE_REG, 1);
}
/**
* @brief Read the 256 bit HMAC.
*/
static inline void hmac_ll_read_result_256(uint32_t *result)
{
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < SHA256_DIGEST_SZ / REG_WIDTH; i++) {
result[i] = REG_READ(HMAC_RDATA_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Clean the HMAC result provided to other hardware.
*/
static inline void hmac_ll_clean(void)
{
REG_WRITE(HMAC_SET_INVALIDATE_DS_REG, 1);
REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1);
}
/**
* @brief Signals that the following block will be the padded last block.
*/
static inline void hmac_ll_msg_padding(void)
{
REG_WRITE(HMAC_SET_MESSAGE_PAD_REG, 1);
}
/**
* @brief Signals that all blocks have been written and a padding block will automatically be applied by hardware.
*
* Only applies if the message length is a multiple of 512 bits.
* See ESP32C3 TRM HMAC chapter for more details.
*/
static inline void hmac_ll_msg_end(void)
{
REG_WRITE(HMAC_SET_MESSAGE_END_REG, 1);
}
/**
* @brief The message including padding fits into one block, so no further action needs to be taken.
*
* This is called after the one-block-message has been written.
*/
static inline void hmac_ll_msg_one_block(void)
{
REG_WRITE(HMAC_ONE_BLOCK_REG, 1);
}
/**
* @brief Indicate that more blocks will be written after the last block.
*/
static inline void hmac_ll_msg_continue(void)
{
REG_WRITE(HMAC_SET_MESSAGE_ING_REG, 1);
}
/**
* @brief Clear the HMAC result.
*
* Use this after reading the HMAC result or if aborting after any of the other steps above.
*/
static inline void hmac_ll_calc_finish(void)
{
REG_WRITE(HMAC_SET_RESULT_FINISH_REG, 2);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,913 @@
// 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.
// The LL layer for I2C register operations
#pragma once
#include "soc/i2c_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2c_types.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_rom_sys.h"
#ifdef __cplusplus
extern "C" {
#endif
#define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */
/**
* @brief I2C hardware cmd register filed.
*/
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 clkm_div; /*!< I2C core clock devider */
uint16_t scl_low; /*!< I2C scl low period */
uint16_t scl_high; /*!< I2C scl hight period */
uint16_t scl_wait_high; /*!< I2C scl wait_high 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 6 /*!<I2C restart command */
#define I2C_LL_CMD_WRITE 1 /*!<I2C write command */
#define I2C_LL_CMD_READ 3 /*!<I2C read command */
#define I2C_LL_CMD_STOP 2 /*!<I2C stop command */
#define I2C_LL_CMD_END 4 /*!<I2C end command */
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (&I2C0)
// 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_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
// 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_WM_INT_ENA_M)
// I2C slave RX interrupt bitmap
#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M)
// I2C source clock
#define I2C_LL_CLK_SRC_FREQ(src_clk) (((src_clk) == I2C_SCLK_RTC) ? 20*1000*1000 : 40*1000*1000); // Another clock is XTAL clock
// delay time after rtc_clk swiching on
#define DELAY_RTC_CLK_SWITCH (5)
// I2C max timeout value
#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V
/**
* @brief Calculate I2C bus frequency
* Note that the clock accuracy is affected by the external pull-up resistor,
* here we try to to calculate a configuration parameter which is close to the required clock.
* But in I2C communication, the clock accuracy is not very concerned.
*
* @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 clkm_div = source_clk / (bus_freq * 1024) +1;
uint32_t sclk_freq = source_clk / clkm_div;
uint32_t half_cycle = sclk_freq / bus_freq / 2;
//SCL
clk_cal->clkm_div = clkm_div;
clk_cal->scl_low = half_cycle;
// default, scl_wait_high < scl_high
int scl_wait_high = (bus_freq <= 50000) ? 0 : (half_cycle / 8); // compensate the time when freq > 50K
clk_cal->scl_wait_high = scl_wait_high;
clk_cal->scl_high = half_cycle - scl_wait_high;
clk_cal->sda_hold = half_cycle / 4;
// scl_wait_high < sda_sample <= scl_high
clk_cal->sda_sample = half_cycle / 2;
clk_cal->setup = half_cycle;
clk_cal->hold = half_cycle;
//default we set the timeout value to about 10 bus cycles
// log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2)
clk_cal->tout = (int)(sizeof(half_cycle) * 8 - __builtin_clz(5 * half_cycle)) + 2;
}
/**
* @brief Update I2C configuration
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_update(i2c_dev_t *hw)
{
hw->ctr.conf_upgate = 1;
}
/**
* @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)
{
hw->clk_conf.sclk_div_num = bus_cfg->clkm_div - 1;
//scl period
hw->scl_low_period.period = bus_cfg->scl_low - 1;
hw->scl_high_period.period = bus_cfg->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 - 1;
hw->scl_stop_hold.time = bus_cfg->hold;
hw->timeout.time_out_value = bus_cfg->tout;
hw->timeout.time_out_en = 1;
}
/**
* @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 core clock cycle, hight_period > 2)
* @param low_period The I2C SCL low period (in core clock cycle, low_period > 1)
*
* @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 - 1;
hw->scl_high_period.period = hight_period - 10;
hw->scl_high_period.scl_wait_high_period = hight_period - hw->scl_high_period.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 (2^tout in core clock cycle)
*
* @return None
*/
static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout)
{
hw->timeout.time_out_value = 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 core clock cycle)
* @param start_hold The start condition hold period (in core clock 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 - 1;
}
/**
* @brief Configure I2C stop timing
*
* @param hw Beginning address of the peripheral registers
* @param stop_setup The stop condition setup period (in core clock cycle)
* @param stop_hold The stop condition hold period (in core clock 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 core clock cycle)
* @param sda_hold The SDA hold time (in core clock 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_wm_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_wm_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->sr.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->sr.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->sr.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.time_out_value;
}
/**
* @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 + 1;
}
/**
* @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 + hw->scl_high_period.scl_wait_high_period;
*low_period = hw->scl_low_period.period + 1;
}
/**
* @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)
{
for (int i = 0; i< len; i++) {
hw->fifo_data.data = 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] = 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->filter_cfg.scl_thres = filter_num;
hw->filter_cfg.sda_thres = filter_num;
hw->filter_cfg.scl_en = 1;
hw->filter_cfg.sda_en = 1;
} else {
hw->filter_cfg.scl_en = 0;
hw->filter_cfg.sda_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->filter_cfg.scl_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)
{
hw->ctr.fsm_rst = 1;
}
/**
* @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)
{
hw->scl_sp_conf.scl_rst_slv_num = 9;
hw->scl_sp_conf.scl_rst_slv_en = 0;
hw->ctr.conf_upgate = 1;
hw->scl_sp_conf.scl_rst_slv_en = 1;
}
/**
* @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)
{
// rtc_clk needs to switch on.
if (src_clk == I2C_SCLK_RTC) {
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
esp_rom_delay_us(DELAY_RTC_CLK_SWITCH);
}
// src_clk : (1) for RTC_CLK, (0) for XTAL
hw->clk_conf.sclk_sel = (src_clk == I2C_SCLK_RTC) ? 1 : 0;
}
/**
* @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.nack) {
*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_wm) {
*event = I2C_INTR_EVENT_TXFIFO_EMPTY;
} else if (int_sts.trans_complete) {
*event = I2C_INTR_EVENT_TRANS_DONE;
} else if (int_sts.rx_fifo_wm) {
*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.clk_en = 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;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,912 @@
// 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 soc/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32-S3 I2S register operations
#pragma once
#include <stdbool.h>
#include <stdlib.h>
#include "soc/i2s_periph.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) : NULL)
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
/**
* @brief Reset rx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Reset tx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Enable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Disable rx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Disable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Enable tx interrupt
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Reset dma in
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Reset dma out
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Reset tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Reset rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Start out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Start tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_tx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Start in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_in_link(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Start rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_start_rx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Stop out link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_out_link(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Stop tx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_tx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Stop in link
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_in_link(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Stop rx
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Enable dma
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_enable_dma(i2s_dev_t *hw)
{
abort(); // TODO ESP32-C3 IDF-2098
// //Enable and configure DMA
// typeof(hw->lc_conf) lc_conf;
// lc_conf.val = 0;
// lc_conf.out_eof_mode = 1;
}
/**
* @brief Get I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get interrupt status
*/
static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->int_st.val;
}
/**
* @brief Clear I2S interrupt status
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to clear interrupt status
*/
static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Get I2S out eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get out eof des address
*/
static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->out_eof_des_addr;
}
/**
* @brief Get I2S in eof des address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get in eof des address
*/
static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->in_eof_des_addr;
}
/**
* @brief Get I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx fifo mode
*/
static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->fifo_conf.tx_fifo_mod;
}
/**
* @brief Set I2S tx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mode
*/
static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Get I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx fifo mode
*/
static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->fifo_conf.rx_fifo_mod;
}
/**
* @brief Set I2S rx fifo mode
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mode
*/
static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S in link address
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set in link address
*/
static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx eof num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx eof num
*/
static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Get I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fp
*/
static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->pdm_freq_conf.tx_pdm_fp;
}
/**
* @brief Get I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx pdm fs
*/
static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->pdm_freq_conf.tx_pdm_fs;
}
/**
* @brief Set I2S tx pdm fp
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fp
*/
static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx pdm fs
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm fs
*/
static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Get I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx sinc dsr 16 en
*/
static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->pdm_conf.rx_sinc_dsr_16_en;
}
/**
* @brief Set I2S clkm div num
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div num
*/
static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S clkm div b
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div b
*/
static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S clkm div a
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clkm div a
*/
static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S clk sel
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set clk sel
*/
static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @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_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx bits mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx bits mod
*/
static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx sinc dsr 16 en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx sinc dsr 16 en
*/
static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S dscr en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set dscr en
*/
static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S lcd en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set lcd en
*/
static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S camera en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set camera en
*/
static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S pcm2pdm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pcm2pdm conv en
*/
static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S TX to MSB Alignment Standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw)
{
}
static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S TX to PCM long standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S RX to PCM long standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S RX to PCM short standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S RX to philip standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S TX to PCM short standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S TX to philip standard
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw)
{
}
/**
* @brief Set I2S pdm2pcm conv en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set pdm2pcm conv en
*/
static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx pdm en
*/
static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx pdm en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx pdm en
*/
static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx fifo mod force en
*/
static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx fifo mod force en
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx fifo mod force en
*/
static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx right first
*/
static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx right first
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx right first
*/
static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx slave mod
*/
static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx slave mod
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx slave mod
*/
static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Get I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get tx msb right
*/
static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->conf.tx_msb_right;
}
/**
* @brief Get I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to get rx msb right
*/
static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val)
{
abort(); // TODO ESP32-C3 IDF-2098
// *val = hw->conf.rx_msb_right;
}
/**
* @brief Set I2S tx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx msb right
*/
static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx msb right
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx msb right
*/
static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx mono
*/
static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S rx mono
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx mono
*/
static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S tx sinc osr2
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx sinc osr2
*/
static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
/**
* @brief Set I2S sig loopback
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set sig loopback
*/
static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val)
{
abort(); // TODO ESP32-C3 IDF-2098
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,152 @@
// 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 "soc/interrupt_core0_reg.h"
#include "riscv/interrupt.h"
#include "riscv/csr.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)
{
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_intc_int_enable(mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
}
/**
* @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)
{
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_intc_int_disable(mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
}
/**
* @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 intr_handler_get(intr);
}
/**
* @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)
{
intr_handler_set(intr, (void *)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 intr_handler_get_arg(intr);
}
/**
* @brief Disables interrupts that are not located in iram
*
* @param newmask mask of interrupts TO KEEP ENABLED (note: this is probably a bug, see IDF-2308)
* @return oldmask previous interrupt mask value
*/
static inline uint32_t intr_cntrl_ll_disable_int_mask(uint32_t newmask)
{
// Disable interrupts in order to atomically update the interrupt enable register
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
uint32_t old_int_enable = REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG);
REG_WRITE(INTERRUPT_CORE0_CPU_INT_ENABLE_REG, old_int_enable & newmask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
return old_int_enable;
}
/**
* @brief Enables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be enabled
*/
static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
{
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_intc_int_enable(newmask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
}
/**
* @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)
{
REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr);
}
/**
* @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 intr_cntrl_ll_set_int_level(int intr, int level)
{
esprv_intc_int_set_priority(intr, level);
}
/**
* @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 intr_cntrl_ll_set_int_type(int intr, int_type_t type)
{
esprv_intc_int_set_type(BIT(intr), type);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,518 @@
// 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.
// 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"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
/**
* @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)
{
uint32_t clk_sel_val = 0;
if (slow_clk_sel == LEDC_SLOW_CLK_APB) {
clk_sel_val = 1;
} else if (slow_clk_sel == LEDC_SLOW_CLK_RTC8M) {
clk_sel_val = 2;
} else if (slow_clk_sel == LEDC_SLOW_CLK_XTAL) {
clk_sel_val = 3;
}
hw->conf.apb_clk_sel = clk_sel_val;
}
/**
* @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)
{
uint32_t clk_sel_val = hw->conf.apb_clk_sel;
if (clk_sel_val == 1) {
*slow_clk_sel = LEDC_SLOW_CLK_APB;
} else if (clk_sel_val == 2) {
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
}
}
/**
* @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)
{
if (clk_src == LEDC_REF_TICK) {
//REF_TICK can only be used when APB is selected.
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 1;
hw->conf.apb_clk_sel = 1;
} else {
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 0;
}
}
/**
* @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 == 1) {
*clk_src = LEDC_REF_TICK;
} else {
*clk_src = LEDC_APB_CLK;
}
}
/**
* @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)
{
uint32_t 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 = LEDC_DUTY_CHNG_END_LSCH0_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 = LEDC_DUTY_CHNG_END_LSCH0_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 = LEDC_DUTY_CHNG_END_LSCH0_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

View File

@ -0,0 +1,446 @@
// 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/sensitive_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* === globals ====
*/
#ifndef SRAM_IRAM_START
#define SRAM_IRAM_START 0x4037C000
#endif
#ifndef SRAM_DRAM_START
#define SRAM_DRAM_START 0x3FC7C000
#endif
/* ICache size is fixed to 16KB on ESP32-C3 */
#ifndef ICACHE_SIZE
#define ICACHE_SIZE 0x4000
#endif
#ifndef I_D_SRAM_SEGMENT_SIZE
#define I_D_SRAM_SEGMENT_SIZE 0x20000
#endif
#ifndef I_D_SRAM_OFFSET
#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START)
#endif
/* 2nd stage bootloader iram_loader_seg start address */
#ifndef SRAM_DRAM_END
#define SRAM_DRAM_END (0x403D0000 - I_D_SRAM_OFFSET)
#endif
#ifndef SRAM_IRAM_ORG
#define SRAM_IRAM_ORG (SRAM_IRAM_START + ICACHE_SIZE)
#endif
#ifndef SRAM_DRAM_ORG
#define SRAM_DRAM_ORG (SRAM_DRAM_START + ICACHE_SIZE)
#endif
#ifndef I_D_SRAM_SIZE
#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG
#endif
#define I_D_SPLIT_LINE_SHIFT 0x9
#define MAP_DRAM_TO_IRAM(addr) (addr - SRAM_DRAM_START + SRAM_IRAM_START)
#define MAP_IRAM_TO_DRAM(addr) (addr - SRAM_IRAM_START + SRAM_DRAM_START)
static inline void memprot_ll_set_iram0_dram0_split_line_lock(bool lock)
{
REG_WRITE(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG, lock ? 1 : 0);
}
static inline bool memprot_ll_get_iram0_dram0_split_line_lock(void)
{
return REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG) == 1;
}
/**
* === IRAM0 ====
*/
//16kB (CACHE)
#define IRAM0_SRAM_LEVEL_0_LOW SRAM_IRAM_START //0x40370000
#define IRAM0_SRAM_LEVEL_0_HIGH (IRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x4037FFFF
//128kB (LEVEL 1)
#define IRAM0_SRAM_LEVEL_1_LOW (IRAM0_SRAM_LEVEL_0_HIGH + 0x1) //0x40380000
#define IRAM0_SRAM_LEVEL_1_HIGH (IRAM0_SRAM_LEVEL_1_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x4039FFFF
//128kB (LEVEL 2)
#define IRAM0_SRAM_LEVEL_2_LOW (IRAM0_SRAM_LEVEL_1_HIGH + 0x1) //0x403A0000
#define IRAM0_SRAM_LEVEL_2_HIGH (IRAM0_SRAM_LEVEL_2_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x403BFFFF
//128kB (LEVEL 3)
#define IRAM0_SRAM_LEVEL_3_LOW (IRAM0_SRAM_LEVEL_2_HIGH + 0x1) //0x403C0000
#define IRAM0_SRAM_LEVEL_3_HIGH (IRAM0_SRAM_LEVEL_3_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x403DFFFF
//permission bits
#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R 0x1
#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W 0x2
#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_F 0x4
static inline uint32_t memprot_ll_iram0_get_intr_source_num(void)
{
return ETS_CORE0_IRAM0_PMS_INTR_SOURCE;
}
/* SPLIT LINE */
static inline void memprot_ll_set_iram0_split_line(const void *line_addr, uint32_t sensitive_reg)
{
uint32_t addr = (uint32_t)line_addr;
assert( addr >= IRAM0_SRAM_LEVEL_1_LOW && addr <= IRAM0_SRAM_LEVEL_3_HIGH );
uint32_t category[3] = {0};
if (addr <= IRAM0_SRAM_LEVEL_1_HIGH) {
category[0] = 0x2;
category[1] = category[2] = 0x3;
} else if (addr >= IRAM0_SRAM_LEVEL_2_LOW && addr <= IRAM0_SRAM_LEVEL_2_HIGH) {
category[1] = 0x2;
category[2] = 0x3;
} else {
category[2] = 0x2;
}
//category bits are the same for all areas
uint32_t category_bits =
(category[0] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_0_S) |
(category[1] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_1_S) |
(category[2] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_2_S);
uint32_t conf_addr = ((addr >> I_D_SPLIT_LINE_SHIFT) & SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_V) << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_S;
uint32_t reg_cfg = conf_addr | category_bits;
REG_WRITE(sensitive_reg, reg_cfg);
}
/* can be both IRAM0/DRAM0 address */
static inline void memprot_ll_set_iram0_split_line_main_I_D(const void *line_addr)
{
memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_1_REG);
}
static inline void memprot_ll_set_iram0_split_line_I_0(const void *line_addr)
{
memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG);
}
static inline void memprot_ll_set_iram0_split_line_I_1(const void *line_addr)
{
memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG);
}
/* PMS */
static inline void memprot_ll_iram0_set_pms_lock(bool lock)
{
REG_WRITE(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0);
}
static inline bool memprot_ll_iram0_get_pms_lock(void)
{
return REG_READ(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG) == 1;
}
//world_0 permissions
static inline uint32_t memprot_ll_iram0_set_permissions(bool r, bool w, bool x)
{
uint32_t permissions = 0;
if ( r ) {
permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R;
}
if ( w ) {
permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W;
}
if ( x ) {
permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_F;
}
return permissions;
}
static inline void memprot_ll_iram0_set_pms_area_0(bool r, bool w, bool x)
{
REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0, memprot_ll_iram0_set_permissions(r, w, x));
}
static inline void memprot_ll_iram0_set_pms_area_1(bool r, bool w, bool x)
{
REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1, memprot_ll_iram0_set_permissions(r, w, x));
}
static inline void memprot_ll_iram0_set_pms_area_2(bool r, bool w, bool x)
{
REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2, memprot_ll_iram0_set_permissions(r, w, x));
}
static inline void memprot_ll_iram0_set_pms_area_3(bool r, bool w, bool x)
{
REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3, memprot_ll_iram0_set_permissions(r, w, x));
}
/* MONITOR */
static inline void memprot_ll_iram0_set_monitor_lock(bool lock)
{
REG_WRITE(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0);
}
static inline bool memprot_ll_iram0_get_monitor_lock(void)
{
return REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG) == 1;
}
static inline void memprot_ll_iram0_set_monitor_en(bool enable)
{
if ( enable ) {
REG_SET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN );
} else {
REG_CLR_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN );
}
}
static inline bool memprot_ll_iram0_get_monitor_en(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN ) == 1;
}
static inline void memprot_ll_iram0_clear_monitor_intr(void)
{
REG_CLR_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR );
}
static inline uint32_t memprot_ll_iram0_get_monitor_status_intr(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_INTR );
}
static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_wr(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_WR );
}
static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_loadstore(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_LOADSTORE );
}
static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_world(void)
{
return REG_GET_FIELD( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_WORLD );
}
static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_addr(void)
{
return REG_GET_FIELD( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR );
}
/**
* === DRAM0 ====
*/
//cache not available from DRAM
#define DRAM0_SRAM_LEVEL_0_LOW SRAM_DRAM_START //0x3FC7C000
#define DRAM0_SRAM_LEVEL_0_HIGH (DRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x3FC7FFFF
//128kB
#define DRAM0_SRAM_LEVEL_1_LOW (DRAM0_SRAM_LEVEL_0_HIGH + 0x1) //0x3FC80000
#define DRAM0_SRAM_LEVEL_1_HIGH (DRAM0_SRAM_LEVEL_1_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FC9FFFF
//128kB
#define DRAM0_SRAM_LEVEL_2_LOW (DRAM0_SRAM_LEVEL_1_HIGH + 0x1) //0x3FCA0000
#define DRAM0_SRAM_LEVEL_2_HIGH (DRAM0_SRAM_LEVEL_2_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FCBFFFF
//128kB
#define DRAM0_SRAM_LEVEL_3_LOW (DRAM0_SRAM_LEVEL_2_HIGH + 0x1) //0x3FCC0000
#define DRAM0_SRAM_LEVEL_3_HIGH (DRAM0_SRAM_LEVEL_3_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FCDFFFF
#define SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W 0x2
#define SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R 0x1
static inline uint32_t memprot_ll_dram0_get_intr_source_num(void)
{
return ETS_CORE0_DRAM0_PMS_INTR_SOURCE;
}
/* SPLIT LINE */
static inline void memprot_ll_set_dram0_split_line(const void *line_addr, uint32_t sensitive_reg)
{
uint32_t addr = (uint32_t)line_addr;
assert( addr >= DRAM0_SRAM_LEVEL_1_LOW && addr <= DRAM0_SRAM_LEVEL_3_HIGH );
uint32_t category[3] = {0};
if (addr <= DRAM0_SRAM_LEVEL_1_HIGH) {
category[0] = 0x2;
category[1] = category[2] = 0x3;
} else if (addr >= DRAM0_SRAM_LEVEL_2_LOW && addr <= DRAM0_SRAM_LEVEL_2_HIGH) {
category[1] = 0x2;
category[2] = 0x3;
} else {
category[2] = 0x2;
}
//category bits are the same for all areas
uint32_t category_bits =
(category[0] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_0_S) |
(category[1] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_1_S) |
(category[2] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_2_S);
uint32_t conf_addr = ((addr >> I_D_SPLIT_LINE_SHIFT) & SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_V) << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_S;
uint32_t reg_cfg = conf_addr | category_bits;
REG_WRITE(sensitive_reg, reg_cfg);
}
static inline void memprot_ll_set_dram0_split_line_D_0(const void *line_addr)
{
memprot_ll_set_dram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG);
}
static inline void memprot_ll_set_dram0_split_line_D_1(const void *line_addr)
{
memprot_ll_set_dram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG);
}
/* PMS */
static inline void memprot_ll_dram0_set_pms_lock(bool lock)
{
REG_WRITE(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0);
}
static inline bool memprot_ll_dram0_get_pms_lock(void)
{
return REG_READ(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG) == 1;
}
static inline uint32_t memprot_ll_dram0_set_permissions(bool r, bool w)
{
uint32_t permissions = 0;
if ( r ) {
permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R;
}
if ( w ) {
permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W;
}
return permissions;
}
static inline void memprot_ll_dram0_set_pms_area_0(bool r, bool w)
{
REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0, memprot_ll_dram0_set_permissions(r, w));
}
static inline void memprot_ll_dram0_set_pms_area_1(bool r, bool w)
{
REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1, memprot_ll_dram0_set_permissions(r, w));
}
static inline void memprot_ll_dram0_set_pms_area_2(bool r, bool w)
{
REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2, memprot_ll_dram0_set_permissions(r, w));
}
static inline void memprot_ll_dram0_set_pms_area_3(bool r, bool w)
{
REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3, memprot_ll_dram0_set_permissions(r, w));
}
/* MONITOR */
static inline void memprot_ll_dram0_set_monitor_lock(bool lock)
{
REG_WRITE(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0);
}
static inline bool memprot_ll_dram0_get_monitor_lock(void)
{
return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG) == 1;
}
static inline void memprot_ll_dram0_set_monitor_en(bool enable)
{
if ( enable ) {
REG_SET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN );
} else {
REG_CLR_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN );
}
}
static inline bool memprot_ll_dram0_get_monitor_en(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN ) == 1;
}
static inline void memprot_ll_dram0_clear_monitor_intr(void)
{
REG_CLR_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_intr(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_INTR );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_lock(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_LOCK );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_world(void)
{
return REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_WORLD );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_addr(void)
{
return REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_wr(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_3_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_WR );
}
static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_byte_en(void)
{
return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_BYTEEN );
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,53 @@
// 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/mpu_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This LL is currently unused for ESP32-C3 - cleanup is TODO ESP32-C3 IDF-2375 */
static inline uint32_t mpu_ll_id_to_addr(int id)
{
abort();
}
static inline void mpu_ll_set_region_rw(uint32_t addr)
{
abort();
}
static inline void mpu_ll_set_region_rwx(uint32_t addr)
{
abort();
}
static inline void mpu_ll_set_region_x(uint32_t addr)
{
abort();
}
static inline void mpu_ll_set_region_illegal(uint32_t addr)
{
abort();
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,254 @@
// 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.
// 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 "soc/timer_periph.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;
}
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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;
}
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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;
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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;
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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;
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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)
{
hw->wdt_config1.clk_prescale = prescaler;
//Config registers are updated asynchronously
hw->wdt_config0.conf_update_en = 1;
}
/**
* @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
*
* Locking the MWDT will prevent any of the MWDT's registers from being modified
*
* @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.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,502 @@
// 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/rmt_struct.h"
#include "soc/soc_caps.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,2], and rx_channel belongs to [0,2]
static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.clk_en = enable; // register clock gating
dev->sys_conf.mem_clk_force_on = enable; // memory clock gating
}
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.mem_force_pu = !enable;
dev->sys_conf.mem_force_pd = enable;
}
static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev)
{
// the RTC domain can also power down RMT memory
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu);
}
static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable)
{
dev->sys_conf.fifo_mask = enable;
}
static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b)
{
// Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b)
dev->sys_conf.sclk_active = 0;
dev->sys_conf.sclk_sel = src;
dev->sys_conf.sclk_div_num = div_num;
dev->sys_conf.sclk_div_a = div_a;
dev->sys_conf.sclk_div_b = div_b;
dev->sys_conf.sclk_active = 1;
}
static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel)
{
return dev->sys_conf.sclk_sel;
}
static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
dev->ref_cnt_rst.val |= (1 << channel);
}
static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask)
{
dev->ref_cnt_rst.val |= channel_mask;
}
static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
dev->ref_cnt_rst.val |= (1 << (channel + 2));
}
static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_conf[channel].mem_rd_rst = 1;
dev->tx_conf[channel].mem_rd_rst = 0;
dev->tx_conf[channel].mem_rst = 1;
dev->tx_conf[channel].mem_rst = 0;
}
static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->rx_conf[channel].conf1.mem_wr_rst = 1;
dev->rx_conf[channel].conf1.mem_wr_rst = 0;
dev->rx_conf[channel].conf1.mem_rst = 1;
dev->rx_conf[channel].conf1.mem_rst = 0;
}
static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_conf[channel].conf_update = 1;
dev->tx_conf[channel].tx_start = 1;
}
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_conf[channel].tx_stop = 1;
dev->tx_conf[channel].conf_update = 1;
}
static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->rx_conf[channel].conf1.rx_en = enable;
dev->rx_conf[channel].conf1.conf_update = 1;
}
static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->tx_conf[channel].mem_size = block_num;
}
static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->rx_conf[channel].conf0.mem_size = block_num;
}
static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_conf[channel].mem_size;
}
static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_conf[channel].conf0.mem_size;
}
static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
dev->tx_conf[channel].div_cnt = div;
}
static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
dev->rx_conf[channel].conf0.div_cnt = div;
}
static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_conf[channel].div_cnt;
}
static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_conf[channel].conf0.div_cnt;
}
static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_conf[channel].mem_tx_wrap_en = enable;
}
static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
{
dev->rx_conf[channel].conf0.idle_thres = thres;
}
static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_conf[channel].conf0.idle_thres;
}
static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner)
{
dev->rx_conf[channel].conf1.mem_owner = owner;
}
static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_conf[channel].conf1.mem_owner;
}
static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_conf[channel].tx_conti_mode = enable;
}
static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_conf[channel].tx_conti_mode;
}
static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count)
{
dev->tx_lim[channel].tx_loop_num = count;
}
static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_lim[channel].loop_count_reset = 1;
dev->tx_lim[channel].loop_count_reset = 0;
}
static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_lim[channel].tx_loop_cnt_en = enable;
}
static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable)
{
dev->tx_sim.en = enable;
}
static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_sim.val |= 1 << channel;
}
static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_sim.val &= ~(1 << channel);
}
static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->rx_conf[channel].conf1.rx_filter_en = enable;
}
static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
{
dev->rx_conf[channel].conf1.rx_filter_thres = thres;
}
static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_conf[channel].idle_out_en = enable;
}
static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_conf[channel].idle_out_en;
}
static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->tx_conf[channel].idle_out_lv = level;
}
static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_conf[channel].idle_out_lv;
}
static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_status[channel].val;
}
static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_status[channel].val;
}
static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->tx_lim[channel].limit = limit;
}
static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->rx_lim[channel].rx_lim = limit;
}
static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel)
{
return dev->rx_lim[channel].rx_lim;
}
static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << channel);
} else {
dev->int_ena.val &= ~(1 << channel);
}
}
static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 4));
} else {
dev->int_ena.val &= ~(1 << (channel + 4));
}
}
static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 2));
} else {
dev->int_ena.val &= ~(1 << (channel + 2));
}
}
static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 6));
} else {
dev->int_ena.val &= ~(1 << (channel + 6));
}
}
static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 8));
} else {
dev->int_ena.val &= ~(1 << (channel + 8));
}
}
static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 12));
} else {
dev->int_ena.val &= ~(1 << (channel + 12));
}
}
static inline void rmt_ll_enable_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
if (enable) {
dev->int_ena.val |= (1 << (channel + 10));
} else {
dev->int_ena.val &= ~(1 << (channel + 10));
}
}
static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel));
}
static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 2));
}
static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 4));
}
static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 6));
}
static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 8));
}
static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 12));
}
static inline void rmt_ll_clear_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 10));
}
static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev)
{
return dev->int_st.val & 0x03;
}
static inline uint32_t rmt_ll_get_rx_end_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 2) & 0x03;
}
static inline uint32_t rmt_ll_get_tx_err_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 4) & 0x03;
}
static inline uint32_t rmt_ll_get_rx_err_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 6) & 0x03;
}
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 8) & 0x03;
}
static inline uint32_t rmt_ll_get_rx_thres_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 10) & 0x03;
}
static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev)
{
return (dev->int_st.val >> 12) & 0x03;
}
static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
// In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
typeof(dev->tx_carrier[0]) reg;
reg.high = high_ticks;
reg.low = low_ticks;
dev->tx_carrier[channel].val = reg.val;
}
static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
typeof(dev->rx_carrier[0]) reg;
reg.high_thres = high_ticks;
reg.low_thres = low_ticks;
dev->rx_carrier[channel].val = reg.val;
}
static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks)
{
*high_ticks = dev->tx_carrier[channel].high;
*low_ticks = dev->tx_carrier[channel].low;
}
static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks)
{
*high_ticks = dev->rx_carrier[channel].high_thres;
*low_ticks = dev->rx_carrier[channel].low_thres;
}
static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_conf[channel].carrier_en = enable;
}
static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->rx_conf[channel].conf0.carrier_en = enable;
}
static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->tx_conf[channel].carrier_out_lv = level;
}
static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->rx_conf[channel].conf0.carrier_out_lv = level;
}
// set true, enable carrier in all RMT state (idle, reading, sending)
// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent)
static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_conf[channel].carrier_eff_en = !enable;
}
//Writes items to the specified TX channel memory with the given offset and writen 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 rmt_item32_t *data, uint32_t length, uint32_t off)
{
for (uint32_t i = 0; i < length; i++) {
mem->chan[channel].data32[i + off].val = data[i].val;
}
}
static inline void rmt_ll_rx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->rx_conf[channel].conf1.mem_rx_wrap_en = enable;
}
/************************************************************************************************
* Following Low Level APIs only used for backward compatible, will be deprecated in the IDF v5.0
***********************************************************************************************/
static inline void rmt_ll_set_intr_enable_mask(uint32_t mask)
{
RMT.int_ena.val |= mask;
}
static inline void rmt_ll_clr_intr_enable_mask(uint32_t mask)
{
RMT.int_ena.val &= (~mask);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,67 @@
// 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.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/apb_ctrl_reg.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);
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_MAIN_TIMER_INT_CLR_M);
SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M);
}
static inline uint32_t rtc_cntl_ll_gpio_get_wakeup_pins(void)
{
return GET_PERI_REG_MASK(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS);
}
static inline void rtc_cntl_ll_gpio_set_wakeup_pins(void)
{
REG_CLR_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR);
}
static inline void rtc_cntl_ll_gpio_clear_wakeup_pins(void)
{
REG_SET_BIT(RTC_CNTL_GPIO_WAKEUP_REG, RTC_CNTL_GPIO_WAKEUP_STATUS_CLR);
}
static inline void rtc_cntl_ll_enable_cpu_retention(uint32_t addr)
{
/* write memory address to register */
REG_SET_FIELD(APB_CTRL_RETENTION_CTRL_REG, APB_CTRL_RETENTION_LINK_ADDR, (uint32_t)addr);
/* Enable clock */
REG_SET_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN);
/* Enable retention when cpu sleep enable */
REG_SET_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN);
}
static inline void rtc_cntl_ll_disable_cpu_retention(void)
{
REG_CLR_BIT(RTC_CNTL_RETENTION_CTRL_REG, RTC_CNTL_RETENTION_EN);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,311 @@
// 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.
// 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/efuse_reg.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 (see note).
* @param behavior What action to take when the stage times out
*
* @note The value of of RWDT stage 0 timeout register is special, in
* that an implicit multiplier is applied to that value to produce
* and effective timeout tick value. The multiplier is dependent
* on an EFuse value. Therefore, when configuring stage 0, the valid
* values for the timeout argument are:
* - If Efuse value is 0, any even number between [2,2*UINT32_MAX]
* - If Efuse value is 1, any multiple of 4 between [4,4*UINT32_MAX]
* - If Efuse value is 2, any multiple of 8 between [8,8*UINT32_MAX]
* - If Efuse value is 3, any multiple of 16 between [16,16*UINT32_MAX]
*/
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;
//Account of implicty multiplier applied to stage 0 timeout tick config value
hw->wdt_config1 = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL));
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 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 Enable/Disable chip reset on RWDT timeout.
*
* A chip reset also resets the analog portion of the chip. It will appear as a
* POWERON reset rather than an RTC reset.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_en(rtc_cntl_dev_t *hw, bool enable)
{
hw->wdt_config0.chip_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Set width of chip reset signal
*
* @param hw Start address of the peripheral registers.
* @param width Width of chip reset signal in terms of number of RTC_SLOW_CLK cycles
*/
FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_width(rtc_cntl_dev_t *hw, uint32_t width)
{
hw->wdt_config0.chip_reset_width = width;
}
/**
* @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 "soc/hwcrypto_reg.h"
#include "hal/sha_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Start a new SHA block conversions (no initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_start_block(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_START_REG, 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)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_CONTINUE_REG, 1);
}
/**
* @brief Start a new SHA message conversion using DMA (no initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_start_dma(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_DMA_START_REG, 1);
}
/**
* @brief Continue a SHA message conversion using DMA (initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_continue_dma(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_DMA_CONTINUE_REG, 1);
}
/**
* @brief Load the current hash digest to digest register
*
* @note Happens automatically on ESP32S3
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_load(esp_sha_type sha_type)
{
}
/**
* @brief Sets the number of message blocks to be hashed
*
* @note DMA operation only
*
* @param num_blocks Number of message blocks to process
*/
static inline void sha_ll_set_block_num(size_t num_blocks)
{
REG_WRITE(SHA_BLOCK_NUM_REG, num_blocks);
}
/**
* @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 REG_READ(SHA_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 *data_words = (uint32_t *)input_text;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
for (int i = 0; i < block_word_len; i++) {
REG_WRITE(&reg_addr_buf[i], 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;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < digest_word_len; i++) {
digest_state_words[i] = REG_READ(SHA_H_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Write 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
* @param digest_word_len Length of the message digest
*/
static inline void sha_ll_write_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_H_BASE);
for (int i = 0; i < digest_word_len; i++) {
REG_WRITE(&reg_addr_buf[i], digest_state_words[i]);
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,73 @@
// 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
******************************************************************************/
// The LL layer for ESP32 SIGMADELTA register operations
#pragma once
#include <stdbool.h>
#include "soc/sigmadelta_periph.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)
{
hw->misc.function_clk_en = en;
}
/**
* @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)
{
hw->channel[channel].duty = 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)
{
hw->channel[channel].prescale = prescale;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,52 @@
// 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"
#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};
const int rtc_cntl_c1_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_S};
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_M};
const int rtc_cntl_c0_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_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};
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_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, RTC_CNTL_SW_PROCPU_RST_M);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,109 @@
// 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 ll is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include "gpspi_flash_ll.h"
#include "spimem_flash_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
// For esp32s2, spimem is equivalent to traditional spi peripherals found
// in esp32. Let the spi flash clock reg definitions reflect this.
#define SPI_FLASH_LL_CLKREG_VAL_5MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_10MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_20MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_26MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_40MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_80MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ}
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))
#define spi_flash_ll_hw_get_id(dev) ({int dev_id = spimem_flash_ll_hw_get_id(dev); \
if (dev_id < 0) {\
dev_id = gpspi_flash_ll_hw_get_id(dev);\
}\
dev_id; \
})
typedef union {
gpspi_flash_ll_clock_reg_t gpspi;
spimem_flash_ll_clock_reg_t spimem;
} spi_flash_ll_clock_reg_t;
#ifdef GPSPI_BUILD
#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len)
#define spi_flash_ll_set_buffer_data(dev, buffer, len) gpspi_flash_ll_set_buffer_data((spi_dev_t*)dev, buffer, len)
#define spi_flash_ll_user_start(dev) gpspi_flash_ll_user_start((spi_dev_t*)dev)
#define spi_flash_ll_host_idle(dev) gpspi_flash_ll_host_idle((spi_dev_t*)dev)
#define spi_flash_ll_read_phase(dev) gpspi_flash_ll_read_phase((spi_dev_t*)dev)
#define spi_flash_ll_set_cs_pin(dev, pin) gpspi_flash_ll_set_cs_pin((spi_dev_t*)dev, pin)
#define spi_flash_ll_set_read_mode(dev, read_mode) gpspi_flash_ll_set_read_mode((spi_dev_t*)dev, read_mode)
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_sector(dev) spimem_flash_ll_erase_sector((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_block(dev) spimem_flash_ll_erase_block((spi_mem_dev_t*)dev)
#define spi_flash_ll_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) spimem_flash_ll_get_buffer_data((spi_mem_dev_t*)dev, buffer, read_len)
#define spi_flash_ll_set_buffer_data(dev, buffer, len) spimem_flash_ll_set_buffer_data((spi_mem_dev_t*)dev, buffer, len)
#define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len)
#define spi_flash_ll_user_start(dev) spimem_flash_ll_user_start((spi_mem_dev_t*)dev)
#define spi_flash_ll_host_idle(dev) spimem_flash_ll_host_idle((spi_mem_dev_t*)dev)
#define spi_flash_ll_read_phase(dev) spimem_flash_ll_read_phase((spi_mem_dev_t*)dev)
#define spi_flash_ll_set_cs_pin(dev, pin) spimem_flash_ll_set_cs_pin((spi_mem_dev_t*)dev, pin)
#define spi_flash_ll_set_read_mode(dev, read_mode) spimem_flash_ll_set_read_mode((spi_mem_dev_t*)dev, read_mode)
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,554 @@
// 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 ll is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include <stdlib.h>
#include <sys/param.h> // For MIN/MAX
#include <stdbool.h>
#include <string.h>
#include "soc/spi_periph.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
typedef typeof(SPIMEM1.clock) spimem_flash_ll_clock_reg_t;
//Supported clock register values
#define SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ ((spimem_flash_ll_clock_reg_t){.val=0x000F070F}) ///< Clock set to 5 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00070307}) ///< Clock set to 10 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00030103}) ///< Clock set to 20 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00020002}) ///< Clock set to 26 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00010001}) ///< Clock set to 40 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ ((spimem_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/*------------------------------------------------------------------------------
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_reset(spi_mem_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 spimem_flash_ll_cmd_is_done(const spi_mem_dev_t *dev)
{
return (dev->cmd.val == 0);
}
/**
* Erase the flash chip.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_chip(spi_mem_dev_t *dev)
{
dev->cmd.flash_ce = 1;
}
/**
* Erase the sector, the address should be set by spimem_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_sector(spi_mem_dev_t *dev)
{
dev->ctrl.val = 0;
dev->cmd.flash_se = 1;
}
/**
* Erase the block, the address should be set by spimem_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
{
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_ctrl.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->flash_sus_ctrl.flash_per = 1;
}
/**
* Initialize auto suspend mode, and esp32c3 doesn't support disable auto-suspend.
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->flash_sus_ctrl.flash_pes_en = auto_sus;
}
/**
* Initialize auto resume mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_res Enable/Disable Flash Auto-Resume.
*
*/
static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
{
dev->flash_sus_ctrl.pes_per_en = auto_res;
}
/**
* Setup the flash suspend command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_cmd Flash suspend command.
*
*/
static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
{
dev->flash_sus_cmd.flash_pes_command = sus_cmd;
}
/**
* Setup the flash resume command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param res_cmd Flash resume command.
*
*/
static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
{
dev->flash_sus_cmd.flash_per_command = res_cmd;
}
/**
* Setup the flash read suspend status command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param pesr_cmd Flash read suspend status command.
*
*/
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{
dev->flash_sus_cmd.wait_pesr_command = pesr_cmd;
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
{
dev->flash_sus_ctrl.sus_timeout_cnt = 5;
dev->flash_sus_ctrl.pes_end_en = sus_check_sus_en;
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
{
dev->flash_sus_ctrl.sus_timeout_cnt = 5;
dev->flash_sus_ctrl.per_end_en = res_check_sus_en;
}
/**
* Set 8 bit command to read suspend status
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_conf)
{
dev->flash_sus_ctrl.frd_sus_2b = 0;
dev->flash_sus_ctrl.pesr_end_msk = sus_conf;
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05;
dev->flash_sus_ctrl.flash_per_wait_en = auto_waiti;
dev->flash_sus_ctrl.flash_pes_wait_en = auto_waiti;
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* 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 spimem_flash_ll_set_write_protect(spi_mem_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 ``spimem_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 spimem_flash_ll_get_buffer_data(spi_mem_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 (int 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;
}
}
}
/**
* 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 spimem_flash_ll_set_buffer_data(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
{
// Load data registers, word at a time
int num_words = (length + 3) / 4;
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 ``spimem_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 spimem_flash_ll_program_page(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
{
dev->user.usr_dummy = 0;
spimem_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 spimem_flash_ll_user_start(spi_mem_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 spimem_flash_ll_host_idle(const spi_mem_dev_t *dev)
{
return dev->fsm.spi0_mst_st == 0;
}
/**
* Set phases for user-defined transaction to read
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_read_phase(spi_mem_dev_t *dev)
{
typeof (dev->user) user = {
.usr_command = 1,
.usr_mosi = 0,
.usr_miso = 1,
.usr_addr = 1,
};
dev->user = user;
}
/*------------------------------------------------------------------------------
* 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 spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin)
{
dev->misc.cs0_dis = (pin == 0) ? 0 : 1;
dev->misc.cs1_dis = (pin == 1) ? 0 : 1;
}
/**
* 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 spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M);
ctrl.val |= SPI_MEM_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 spimem_flash_ll_set_clock(spi_mem_dev_t *dev, spimem_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 spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
dev->miso_dlen.usr_miso_bit_len = 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 spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
dev->mosi_dlen.usr_mosi_bit_len = 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 spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_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 spimem_flash_ll_get_addr_bitlen(spi_mem_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 spimem_flash_ll_set_addr_bitlen(spi_mem_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. 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 spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr)
{
dev->addr = addr;
}
/**
* Set the address to send in user 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 spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, 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 spimem_flash_ll_set_dummy(spi_mem_dev_t *dev, uint32_t dummy_n)
{
dev->user.usr_dummy = dummy_n ? 1 : 0;
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
/**
* Set D/Q output level during dummy phase
*
* @param dev Beginning address of the peripheral registers.
* @param out_en whether to enable IO output for dummy phase
* @param out_level dummy output level
*/
static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t out_en, uint32_t out_lev)
{
dev->ctrl.fdummy_out = out_en;
dev->ctrl.q_pol = out_lev;
dev->ctrl.d_pol = out_lev;
}
/**
* Set CS hold time.
*
* @param dev Beginning address of the peripheral registers.
* @param hold_n CS hold time config used by the host.
*/
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,153 @@
// 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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/systimer_reg.h"
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/*******************counter*************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(void)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_CONF_REG, SYS_TIMER_CLK_EN);
}
__attribute__((always_inline)) static inline void systimer_ll_enable_counter(uint32_t counter_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_CONF_REG, 1 << (30 - counter_id));
}
__attribute__((always_inline)) static inline void systimer_ll_counter_can_stall_by_cpu(uint32_t counter_id, uint32_t cpu_id, bool can)
{
if (can) {
REG_SET_BIT(SYS_TIMER_SYSTIMER_CONF_REG, 1 << ((28 - counter_id * 2) - cpu_id));
} else {
REG_CLR_BIT(SYS_TIMER_SYSTIMER_CONF_REG, 1 << ((28 - counter_id * 2) - cpu_id));
}
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(uint32_t counter_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_UNIT0_OP_REG + 4 * counter_id, 1 << 30);
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(uint32_t counter_id)
{
return REG_GET_BIT(SYS_TIMER_SYSTIMER_UNIT0_OP_REG + 4 * counter_id, 1 << 29);
}
__attribute__((always_inline)) static inline void systimer_ll_set_counter_value(uint32_t counter_id, uint64_t value)
{
REG_WRITE(SYS_TIMER_SYSTIMER_UNIT0_LOAD_LO_REG + 8 * counter_id, value & 0xFFFFFFFF);
REG_WRITE(SYS_TIMER_SYSTIMER_UNIT0_LOAD_HI_REG, (value >> 32) & 0xFFFFF);
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(uint32_t counter_id)
{
return REG_READ(SYS_TIMER_SYSTIMER_UNIT0_VALUE_LO_REG + 8 * counter_id);
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(uint32_t counter_id)
{
return REG_READ(SYS_TIMER_SYSTIMER_UNIT0_VALUE_HI_REG + 8 * counter_id);
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(uint32_t counter_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_UNIT0_LOAD_REG + 4 * counter_id, SYS_TIMER_TIMER_UNIT0_LOAD);
}
/*******************alarm*************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_target(uint32_t alarm_id, uint64_t value)
{
REG_WRITE(SYS_TIMER_SYSTIMER_TARGET0_LO_REG + alarm_id * 8, value & 0xFFFFFFFF);
REG_WRITE(SYS_TIMER_SYSTIMER_TARGET0_HI_REG + alarm_id * 8, (value >> 32) & 0xFFFFF);
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_target(uint32_t alarm_id)
{
return ((uint64_t) REG_READ(SYS_TIMER_SYSTIMER_TARGET0_HI_REG + alarm_id * 8) << 32) \
| REG_READ(SYS_TIMER_SYSTIMER_TARGET0_LO_REG + alarm_id * 8);
}
__attribute__((always_inline)) static inline void systimer_ll_connect_alarm_counter(uint32_t alarm_id, uint32_t counter_id)
{
REG_SET_FIELD(SYS_TIMER_SYSTIMER_TARGET0_CONF_REG + 4 * alarm_id, SYS_TIMER_TARGET0_TIMER_UNIT_SEL, counter_id);
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(uint32_t alarm_id)
{
REG_CLR_BIT(SYS_TIMER_SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, SYS_TIMER_TARGET0_PERIOD_MODE);
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(uint32_t alarm_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, SYS_TIMER_TARGET0_PERIOD_MODE);
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(uint32_t alarm_id, uint32_t period)
{
REG_SET_FIELD(SYS_TIMER_SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, SYS_TIMER_TARGET0_PERIOD, period);
}
__attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(uint32_t alarm_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_COMP0_LOAD_REG + alarm_id * 4, SYS_TIMER_TIMER_COMP0_LOAD);
}
__attribute__((always_inline)) static inline void systimer_ll_disable_alarm(uint32_t alarm_id)
{
REG_CLR_BIT(SYS_TIMER_SYSTIMER_CONF_REG, 1 << (24 - alarm_id));
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(uint32_t alarm_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_CONF_REG, 1 << (24 - alarm_id));
}
/*******************interrupt*************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(uint32_t alarm_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_INT_ENA_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_disable_alarm_int(uint32_t alarm_id)
{
REG_CLR_BIT(SYS_TIMER_SYSTIMER_INT_ENA_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(uint32_t alarm_id)
{
return REG_GET_BIT(SYS_TIMER_SYSTIMER_INT_RAW_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(uint32_t alarm_id)
{
REG_SET_BIT(SYS_TIMER_SYSTIMER_INT_CLR_REG, 1 << alarm_id);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,430 @@
// 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.
// 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/timer_types.h"
#include "soc/timer_periph.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_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
typedef struct {
timg_dev_t *dev;
timer_idx_t idx;
} timer_ll_context_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
*
* @return None
*/
static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider)
{
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;
hw->hw_timer[timer_num].config.divcnt_rst = 1;
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 = 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.load_hi = (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.update = 1;
while (hw->hw_timer[timer_num].update.update) {}
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high.hi << 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.alarm_hi = (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.alarm_hi << 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);
}
/**
* @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));
}
/**
* @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.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.val & 0x01;
}
/**
* @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 & 0x01;
}
/**
* @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)
{
// Only "level" interrupts are supported on this target
}
/**
* @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)
{
// Only "level" interrupts are supported on this target
return true;
}
/**
* @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)
{
// edge interrupt is not supported on C3
}
/**
* @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)
{
// edge interrupt is not supported on C3
return false;
}
/**
* @brief Get interrupt status register address.
*
* @param hw Beginning address of the peripheral registers.
*
* @return uint32_t Interrupt status register address
*/
static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw)
{
return (uint32_t) & (hw->int_st.val);
}
static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num)
{
return (1U << timer_num);
}
/**
* @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
*/
static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en)
{
hw->hw_timer[timer_num].config.use_xtal = use_xtal_en;
}
/**
* @brief Get clock source.
*
* @param hal Context of the HAL layer
*
* @return
* - true Use XTAL clock
* - false Use APB clock
*/
static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.use_xtal;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,667 @@
// 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 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 "hal/twai_types.h"
#include "soc/twai_periph.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_STATUS_MS (0x1 << 8) //Miss 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");
/* ---------------------------- 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; //Set command_reg.tr and command_reg.at simultaneously for single shot transmittion request
}
/**
* @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; //Set command_reg.srr and command_reg.at simultaneously for single shot self reception request
}
/* --------------------------- 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)
{
hw->interrupt_enable_reg.val = intr_mask;
}
/* ------------------------ 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 ESP32C3 brp can be any even number between 2 to 32768
*/
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)
{
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;
}
/* ----------------------------- 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)
{
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)
{
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)
{
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 = __builtin_bswap32(code);
uint32_t mask_swapped = __builtin_bswap32(mask);
for (int i = 0; i < 4; i++) {
hw->acceptance_filter.acr[i].byte = ((code_swapped >> (i * 8)) & 0xFF);
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] = 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 = __builtin_bswap32((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 = __builtin_bswap16((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 a remote frame)
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 = __builtin_bswap32(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 = __builtin_bswap16(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 490. Set the divider to 0 to disable CLKOUT.
*
* @param hw Start address of the TWAI registers
* @param divider Divider for CLKOUT (any even number from 2 to 490). Set to 0 to disable CLKOUT
*/
static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider)
{
if (divider >= 2 && divider <= 490) {
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 (255) means a divider of 1
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = 255;
} else {
hw->clock_divider_reg.co = 1;
hw->clock_divider_reg.cd = 0;
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,934 @@
// 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.
// The LL layer for UART register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#include "hal/uart_types.h"
#include "soc/uart_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
// The default fifo depth
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
// Get UART hardware instance with giving uart num
#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (&UART1))
#define UART_LL_MIN_WAKEUP_THRESH (2)
#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
// Define UART interrupts
typedef enum {
UART_INTR_RXFIFO_FULL = (0x1 << 0),
UART_INTR_TXFIFO_EMPTY = (0x1 << 1),
UART_INTR_PARITY_ERR = (0x1 << 2),
UART_INTR_FRAM_ERR = (0x1 << 3),
UART_INTR_RXFIFO_OVF = (0x1 << 4),
UART_INTR_DSR_CHG = (0x1 << 5),
UART_INTR_CTS_CHG = (0x1 << 6),
UART_INTR_BRK_DET = (0x1 << 7),
UART_INTR_RXFIFO_TOUT = (0x1 << 8),
UART_INTR_SW_XON = (0x1 << 9),
UART_INTR_SW_XOFF = (0x1 << 10),
UART_INTR_GLITCH_DET = (0x1 << 11),
UART_INTR_TX_BRK_DONE = (0x1 << 12),
UART_INTR_TX_BRK_IDLE = (0x1 << 13),
UART_INTR_TX_DONE = (0x1 << 14),
UART_INTR_RS485_PARITY_ERR = (0x1 << 15),
UART_INTR_RS485_FRM_ERR = (0x1 << 16),
UART_INTR_RS485_CLASH = (0x1 << 17),
UART_INTR_CMD_CHAR_DET = (0x1 << 18),
} uart_intr_t;
static inline void uart_ll_reset_core(uart_dev_t *hw) {
hw->clk_conf.rst_core = 1;
hw->clk_conf.rst_core = 0;
}
static inline void uart_ll_sclk_enable(uart_dev_t *hw) {
hw->clk_conf.sclk_en = 1;
hw->clk_conf.rx_sclk_en = 1;
hw->clk_conf.tx_sclk_en = 1;
}
static inline void uart_ll_sclk_disable(uart_dev_t *hw) {
hw->clk_conf.sclk_en = 0;
hw->clk_conf.rx_sclk_en = 0;
hw->clk_conf.tx_sclk_en = 0;
}
/**
* @brief Set the UART source clock.
*
* @param hw Beginning address of the peripheral registers.
* @param source_clk The UART source clock. The source clock can be APB clock, RTC clock or XTAL clock.
* If the source clock is RTC/XTAL, the UART can still work when the APB changes.
*
* @return None.
*/
static inline void uart_ll_set_sclk(uart_dev_t *hw, uart_sclk_t source_clk)
{
switch (source_clk) {
default:
case UART_SCLK_APB:
hw->clk_conf.sclk_sel = 1;
break;
case UART_SCLK_RTC:
hw->clk_conf.sclk_sel = 2;
break;
case UART_SCLK_XTAL:
hw->clk_conf.sclk_sel = 3;
break;
}
}
/**
* @brief Get the UART source clock type.
*
* @param hw Beginning address of the peripheral registers.
* @param source_clk The pointer to accept the UART source clock type.
*
* @return None.
*/
static inline void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t *source_clk)
{
switch (hw->clk_conf.sclk_sel) {
default:
case 1:
*source_clk = UART_SCLK_APB;
break;
case 2:
*source_clk = UART_SCLK_RTC;
break;
case 3:
*source_clk = UART_SCLK_XTAL;
break;
}
}
/**
* @brief Get the UART source clock frequency.
*
* @param hw Beginning address of the peripheral registers.
*
* @return Current source clock frequency
*/
static inline uint32_t uart_ll_get_sclk_freq(uart_dev_t *hw)
{
switch (hw->clk_conf.sclk_sel) {
default:
case 1:
return APB_CLK_FREQ;
case 2:
return RTC_CLK_FREQ;
case 3:
return XTAL_CLK_FREQ;
}
}
/**
* @brief Configure the baud-rate.
*
* @param hw Beginning address of the peripheral registers.
* @param baud The baud rate to be set.
*
* @return None
*/
static inline void uart_ll_set_baudrate(uart_dev_t *hw, uint32_t baud)
{
#define DIV_UP(a, b) (((a) + (b) - 1) / (b))
uint32_t sclk_freq = uart_ll_get_sclk_freq(hw);
const uint32_t max_div = BIT(12) - 1; // UART divider integer part only has 12 bits
int sclk_div = DIV_UP(sclk_freq, max_div * baud);
uint32_t clk_div = ((sclk_freq) << 4) / (baud * sclk_div);
// The baud rate configuration register is divided into
// an integer part and a fractional part.
hw->clk_div.div_int = clk_div >> 4;
hw->clk_div.div_frag = clk_div & 0xf;
hw->clk_conf.sclk_div_num = sclk_div - 1;
#undef DIV_UP
}
/**
* @brief Get the current baud-rate.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The current baudrate
*/
static inline uint32_t uart_ll_get_baudrate(uart_dev_t *hw)
{
uint32_t sclk_freq = uart_ll_get_sclk_freq(hw);
typeof(hw->clk_div) div_reg = hw->clk_div;
return ((sclk_freq << 4)) / (((div_reg.div_int << 4) | div_reg.div_frag) * (hw->clk_conf.sclk_div_num + 1));
}
/**
* @brief Enable the UART interrupt based on the given mask.
*
* @param hw Beginning address of the peripheral registers.
* @param mask The bitmap of the interrupts need to be enabled.
*
* @return None
*/
static inline void uart_ll_ena_intr_mask(uart_dev_t *hw, uint32_t mask)
{
hw->int_ena.val |= mask;
}
/**
* @brief Disable the UART interrupt based on the given mask.
*
* @param hw Beginning address of the peripheral registers.
* @param mask The bitmap of the interrupts need to be disabled.
*
* @return None
*/
static inline void uart_ll_disable_intr_mask(uart_dev_t *hw, uint32_t mask)
{
hw->int_ena.val &= (~mask);
}
/**
* @brief Get the UART interrupt status.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The UART interrupt status.
*/
static inline uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw)
{
return hw->int_st.val;
}
/**
* @brief Clear the UART interrupt status based on the given mask.
*
* @param hw Beginning address of the peripheral registers.
* @param mask The bitmap of the interrupts need to be cleared.
*
* @return None
*/
static inline void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask)
{
hw->int_clr.val = mask;
}
/**
* @brief Get status of enabled interrupt.
*
* @param hw Beginning address of the peripheral registers.
*
* @return interrupt enable value
*/
static inline uint32_t uart_ll_get_intr_ena_status(uart_dev_t *hw)
{
return hw->int_ena.val;
}
/**
* @brief Read the UART rxfifo.
*
* @param hw Beginning address of the peripheral registers.
* @param buf The data buffer. The buffer size should be large than 128 byts.
* @param rd_len The data length needs to be read.
*
* @return None.
*/
static inline void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len)
{
for (int i = 0; i < (int)rd_len; i++) {
buf[i] = hw->ahb_fifo.rw_byte;
}
}
/**
* @brief Write byte to the UART txfifo.
*
* @param hw Beginning address of the peripheral registers.
* @param buf The data buffer.
* @param wr_len The data length needs to be writen.
*
* @return None
*/
static inline void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len)
{
for (int i = 0; i < (int)wr_len; i++) {
hw->ahb_fifo.rw_byte = buf[i];
}
}
/**
* @brief Reset the UART hw rxfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None
*/
static inline void uart_ll_rxfifo_rst(uart_dev_t *hw)
{
hw->conf0.rxfifo_rst = 1;
hw->conf0.rxfifo_rst = 0;
}
/**
* @brief Reset the UART hw txfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None
*/
static inline void uart_ll_txfifo_rst(uart_dev_t *hw)
{
hw->conf0.txfifo_rst = 1;
hw->conf0.txfifo_rst = 0;
}
/**
* @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.
*/
static inline uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw)
{
return hw->status.rxfifo_cnt;
}
/**
* @brief Get the writable data length of UART txfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The data length of txfifo can be written.
*/
static inline uint32_t uart_ll_get_txfifo_len(uart_dev_t *hw)
{
return UART_LL_FIFO_DEF_LEN - hw->status.txfifo_cnt;
}
/**
* @brief Configure the UART stop bit.
*
* @param hw Beginning address of the peripheral registers.
* @param stop_bit The stop bit number to be set.
*
* @return None.
*/
static inline void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit)
{
hw->conf0.stop_bit_num = stop_bit;
}
/**
* @brief Get the configuration of the UART stop bit.
*
* @param hw Beginning address of the peripheral registers.
* @param stop_bit The pointer to accept the stop bit configuration
*
* @return None.
*/
static inline void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit)
{
*stop_bit = hw->conf0.stop_bit_num;
}
/**
* @brief Configure the UART parity check mode.
*
* @param hw Beginning address of the peripheral registers.
* @param parity_mode The parity check mode to be set.
*
* @return None.
*/
static inline void uart_ll_set_parity(uart_dev_t *hw, uart_parity_t parity_mode)
{
if (parity_mode != UART_PARITY_DISABLE) {
hw->conf0.parity = parity_mode & 0x1;
}
hw->conf0.parity_en = (parity_mode >> 1) & 0x1;
}
/**
* @brief Get the UART parity check mode configuration.
*
* @param hw Beginning address of the peripheral registers.
* @param parity_mode The pointer to accept the parity check mode configuration.
*
* @return None.
*/
static inline void uart_ll_get_parity(uart_dev_t *hw, uart_parity_t *parity_mode)
{
if (hw->conf0.parity_en) {
*parity_mode = 0X2 | hw->conf0.parity;
} else {
*parity_mode = UART_PARITY_DISABLE;
}
}
/**
* @brief Set the UART rxfifo full threshold value. When the data in rxfifo is more than the threshold value,
* it will produce rxfifo_full_int_raw interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param full_thrhd The full threshold value of the rxfifo. `full_thrhd` should be less than `UART_LL_FIFO_DEF_LEN`.
*
* @return None.
*/
static inline void uart_ll_set_rxfifo_full_thr(uart_dev_t *hw, uint16_t full_thrhd)
{
hw->conf1.rxfifo_full_thrhd = full_thrhd;
}
/**
* @brief Set the txfifo empty threshold. when the data length in txfifo is less than threshold value,
* it will produce txfifo_empty_int_raw interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param empty_thrhd The empty threshold of txfifo.
*
* @return None.
*/
static inline void uart_ll_set_txfifo_empty_thr(uart_dev_t *hw, uint16_t empty_thrhd)
{
hw->conf1.txfifo_empty_thrhd = empty_thrhd;
}
/**
* @brief Set the UART rx-idle threshold value. when receiver takes more time than rx_idle_thrhd to receive a byte data,
* it will produce frame end signal for uhci to stop receiving data.
*
* @param hw Beginning address of the peripheral registers.
* @param rx_idle_thr The rx-idle threshold to be set.
*
* @return None.
*/
static inline void uart_ll_set_rx_idle_thr(uart_dev_t *hw, uint32_t rx_idle_thr)
{
hw->idle_conf.rx_idle_thrhd = rx_idle_thr;
}
/**
* @brief Configure the duration time between transfers.
*
* @param hw Beginning address of the peripheral registers.
* @param idle_num the duration time between transfers.
*
* @return None.
*/
static inline void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num)
{
hw->idle_conf.tx_idle_num = idle_num;
}
/**
* @brief Configure the transmiter to send break chars.
*
* @param hw Beginning address of the peripheral registers.
* @param break_num The number of the break chars need to be send.
*
* @return None.
*/
static inline void uart_ll_tx_break(uart_dev_t *hw, uint32_t break_num)
{
if (break_num > 0) {
hw->txbrk_conf.tx_brk_num = break_num;
hw->conf0.txd_brk = 1;
} else {
hw->conf0.txd_brk = 0;
}
}
/**
* @brief Configure the UART hardware flow control.
*
* @param hw Beginning address of the peripheral registers.
* @param flow_ctrl The hw flow control configuration.
* @param rx_thrs The rx flow control signal will be active if the data length in rxfifo is more than this value.
*
* @return None.
*/
static inline void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs)
{
//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
if (flow_ctrl & UART_HW_FLOWCTRL_RTS) {
hw->mem_conf.rx_flow_thrhd = rx_thrs;
hw->conf1.rx_flow_en = 1;
} else {
hw->conf1.rx_flow_en = 0;
}
if (flow_ctrl & UART_HW_FLOWCTRL_CTS) {
hw->conf0.tx_flow_en = 1;
} else {
hw->conf0.tx_flow_en = 0;
}
}
/**
* @brief Configure the hardware flow control.
*
* @param hw Beginning address of the peripheral registers.
* @param flow_ctrl A pointer to accept the hw flow control configuration.
*
* @return None.
*/
static inline void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t *flow_ctrl)
{
*flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
if (hw->conf1.rx_flow_en) {
*flow_ctrl |= UART_HW_FLOWCTRL_RTS;
}
if (hw->conf0.tx_flow_en) {
*flow_ctrl |= UART_HW_FLOWCTRL_CTS;
}
}
/**
* @brief Configure the software flow control.
*
* @param hw Beginning address of the peripheral registers.
* @param flow_ctrl The UART sofware flow control settings.
* @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false.
*
* @return None.
*/
static inline void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en)
{
if (sw_flow_ctrl_en) {
hw->flow_conf.xonoff_del = 1;
hw->flow_conf.sw_flow_con_en = 1;
hw->swfc_conf1.xon_threshold = flow_ctrl->xon_thrd;
hw->swfc_conf0.xoff_threshold = flow_ctrl->xoff_thrd;
hw->swfc_conf1.xon_char = flow_ctrl->xon_char;
hw->swfc_conf0.xoff_char = flow_ctrl->xoff_char;
} else {
hw->flow_conf.sw_flow_con_en = 0;
hw->flow_conf.xonoff_del = 0;
}
}
/**
* @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param cmd_char The AT cmd char configuration.The configuration member is:
* - cmd_char The AT cmd character
* - char_num The number of received AT cmd char must be equal to or greater than this value
* - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char
* - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char
* - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char
*
* @return None.
*/
static inline void uart_ll_set_at_cmd_char(uart_dev_t *hw, uart_at_cmd_t *cmd_char)
{
hw->at_cmd_char.data = cmd_char->cmd_char;
hw->at_cmd_char.char_num = cmd_char->char_num;
hw->at_cmd_postcnt.post_idle_num = cmd_char->post_idle;
hw->at_cmd_precnt.pre_idle_num = cmd_char->pre_idle;
hw->at_cmd_gaptout.rx_gap_tout = cmd_char->gap_tout;
}
/**
* @brief Set the UART data bit mode.
*
* @param hw Beginning address of the peripheral registers.
* @param data_bit The data bit mode to be set.
*
* @return None.
*/
static inline void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit)
{
hw->conf0.bit_num = data_bit;
}
/**
* @brief Set the rts active level.
*
* @param hw Beginning address of the peripheral registers.
* @param level The rts active level, 0 or 1.
*
* @return None.
*/
static inline void uart_ll_set_rts_active_level(uart_dev_t *hw, int level)
{
hw->conf0.sw_rts = level & 0x1;
}
/**
* @brief Set the dtr active level.
*
* @param hw Beginning address of the peripheral registers.
* @param level The dtr active level, 0 or 1.
*
* @return None.
*/
static inline void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level)
{
hw->conf0.sw_dtr = level & 0x1;
}
/**
* @brief Set the UART wakeup threshold.
*
* @param hw Beginning address of the peripheral registers.
* @param wakeup_thrd The wakeup threshold value to be set. When the input rx edge changes more than this value,
* the UART will active from light sleeping mode.
*
* @return None.
*/
static inline void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
{
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH;
}
/**
* @brief Configure the UART work in normal mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
static inline void uart_ll_set_mode_normal(uart_dev_t *hw)
{
hw->rs485_conf.en = 0;
hw->rs485_conf.tx_rx_en = 0;
hw->rs485_conf.rx_busy_tx_en = 0;
hw->conf0.irda_en = 0;
}
/**
* @brief Configure the UART work in rs485_app_ctrl mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
static inline void uart_ll_set_mode_rs485_app_ctrl(uart_dev_t *hw)
{
// Application software control, remove echo
hw->rs485_conf.rx_busy_tx_en = 1;
hw->conf0.irda_en = 0;
hw->conf0.sw_rts = 0;
hw->conf0.irda_en = 0;
hw->rs485_conf.dl0_en = 1;
hw->rs485_conf.dl1_en = 1;
hw->rs485_conf.en = 1;
}
/**
* @brief Configure the UART work in rs485_half_duplex mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
static inline void uart_ll_set_mode_rs485_half_duplex(uart_dev_t *hw)
{
// Enable receiver, sw_rts = 1 generates low level on RTS pin
hw->conf0.sw_rts = 1;
// Half duplex mode
hw->rs485_conf.tx_rx_en = 0;
// Setting this bit will allow data to be transmitted while receiving data(full-duplex mode).
// But note that this full-duplex mode has no conflict detection function
hw->rs485_conf.rx_busy_tx_en = 0;
hw->conf0.irda_en = 0;
hw->rs485_conf.dl0_en = 1;
hw->rs485_conf.dl1_en = 1;
hw->rs485_conf.en = 1;
}
/**
* @brief Configure the UART work in collision_detect mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
static inline void uart_ll_set_mode_collision_detect(uart_dev_t *hw)
{
hw->conf0.irda_en = 0;
// Enable full-duplex mode
hw->rs485_conf.tx_rx_en = 1;
// Transmitter should send data when the receiver is busy,
hw->rs485_conf.rx_busy_tx_en = 1;
hw->rs485_conf.dl0_en = 1;
hw->rs485_conf.dl1_en = 1;
hw->conf0.sw_rts = 0;
hw->rs485_conf.en = 1;
}
/**
* @brief Configure the UART work in irda mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
static inline void uart_ll_set_mode_irda(uart_dev_t *hw)
{
hw->rs485_conf.en = 0;
hw->rs485_conf.tx_rx_en = 0;
hw->rs485_conf.rx_busy_tx_en = 0;
hw->conf0.sw_rts = 0;
hw->conf0.irda_en = 1;
}
/**
* @brief Set uart mode.
*
* @param hw Beginning address of the peripheral registers.
* @param mode The UART mode to be set.
*
* @return None.
*/
static inline void uart_ll_set_mode(uart_dev_t *hw, uart_mode_t mode)
{
switch (mode) {
default:
case UART_MODE_UART:
uart_ll_set_mode_normal(hw);
break;
case UART_MODE_RS485_COLLISION_DETECT:
uart_ll_set_mode_collision_detect(hw);
break;
case UART_MODE_RS485_APP_CTRL:
uart_ll_set_mode_rs485_app_ctrl(hw);
break;
case UART_MODE_RS485_HALF_DUPLEX:
uart_ll_set_mode_rs485_half_duplex(hw);
break;
case UART_MODE_IRDA:
uart_ll_set_mode_irda(hw);
break;
}
}
/**
* @brief Get the UART AT cmd char configuration.
*
* @param hw Beginning address of the peripheral registers.
* @param cmd_char The Pointer to accept value of UART AT cmd char.
* @param char_num Pointer to accept the repeat number of UART AT cmd char.
*
* @return None.
*/
static inline void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char, uint8_t *char_num)
{
*cmd_char = hw->at_cmd_char.data;
*char_num = hw->at_cmd_char.char_num;
}
/**
* @brief Get the UART wakeup threshold value.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The UART wakeup threshold value.
*/
static inline uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
{
return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH;
}
/**
* @brief Get the UART data bit configuration.
*
* @param hw Beginning address of the peripheral registers.
* @param data_bit The pointer to accept the UART data bit configuration.
*
* @return The bit mode.
*/
static inline void uart_ll_get_data_bit_num(uart_dev_t *hw, uart_word_length_t *data_bit)
{
*data_bit = hw->conf0.bit_num;
}
/**
* @brief Check if the UART sending state machine is in the IDLE state.
*
* @param hw Beginning address of the peripheral registers.
*
* @return True if the state machine is in the IDLE state, otherwise false is returned.
*/
static inline bool uart_ll_is_tx_idle(uart_dev_t *hw)
{
return ((hw->status.txfifo_cnt == 0) && (hw->fsm_status.st_utx_out == 0));
}
/**
* @brief Check if the UART rts flow control is enabled.
*
* @param hw Beginning address of the peripheral registers.
*
* @return True if hw rts flow control is enabled, otherwise false is returned.
*/
static inline bool uart_ll_is_hw_rts_en(uart_dev_t *hw)
{
return hw->conf1.rx_flow_en;
}
/**
* @brief Check if the UART cts flow control is enabled.
*
* @param hw Beginning address of the peripheral registers.
*
* @return True if hw cts flow control is enabled, otherwise false is returned.
*/
static inline bool uart_ll_is_hw_cts_en(uart_dev_t *hw)
{
return hw->conf0.tx_flow_en;
}
/**
* @brief Configure TX signal loop back to RX module, just for the testing purposes
*
* @param hw Beginning address of the peripheral registers.
* @param loop_back_en Set ture to enable the loop back function, else set it false.
*
* @return None
*/
static inline void uart_ll_set_loop_back(uart_dev_t *hw, bool loop_back_en)
{
hw->conf0.loopback = loop_back_en;
}
static inline void uart_ll_xon_force_on(uart_dev_t *hw, bool always_on)
{
hw->flow_conf.force_xon = 1;
if(!always_on) {
hw->flow_conf.force_xon = 0;
}
}
/**
* @brief Inverse the UART signal with the given mask.
*
* @param hw Beginning address of the peripheral registers.
* @param inv_mask The UART signal bitmap needs to be inversed.
* Use the ORred mask of `uart_signal_inv_t`;
*
* @return None.
*/
static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask)
{
typeof(hw->conf0) conf0_reg = hw->conf0;
conf0_reg.irda_tx_inv = (inv_mask & UART_SIGNAL_IRDA_TX_INV) ? 1 : 0;
conf0_reg.irda_rx_inv = (inv_mask & UART_SIGNAL_IRDA_RX_INV) ? 1 : 0;
conf0_reg.rxd_inv = (inv_mask & UART_SIGNAL_RXD_INV) ? 1 : 0;
conf0_reg.cts_inv = (inv_mask & UART_SIGNAL_CTS_INV) ? 1 : 0;
conf0_reg.dsr_inv = (inv_mask & UART_SIGNAL_DSR_INV) ? 1 : 0;
conf0_reg.txd_inv = (inv_mask & UART_SIGNAL_TXD_INV) ? 1 : 0;
conf0_reg.rts_inv = (inv_mask & UART_SIGNAL_RTS_INV) ? 1 : 0;
conf0_reg.dtr_inv = (inv_mask & UART_SIGNAL_DTR_INV) ? 1 : 0;
hw->conf0.val = conf0_reg.val;
}
/**
* @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function.
*
* @param hw Beginning address of the peripheral registers.
* @param tout_thrd The timeout value as UART bit time. The rx timeout function will be disabled if `tout_thrd == 0`.
*
* @return None.
*/
static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd)
{
uint16_t tout_val = tout_thrd;
if(tout_thrd > 0) {
hw->mem_conf.rx_tout_thrhd = tout_val;
hw->conf1.rx_tout_en = 1;
} else {
hw->conf1.rx_tout_en = 0;
}
}
/**
* @brief Get the timeout value for receiver receiving a byte.
*
* @param hw Beginning address of the peripheral registers.
*
* @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0.
*/
static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw)
{
uint16_t tout_thrd = 0;
if(hw->conf1.rx_tout_en > 0) {
tout_thrd = hw->mem_conf.rx_tout_thrhd;
}
return tout_thrd;
}
/**
* @brief Get UART maximum timeout threshold.
*
* @param hw Beginning address of the peripheral registers.
*
* @return maximum timeout threshold.
*/
static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
{
return UART_RX_TOUT_THRHD_V;
}
/**
* @brief Force UART xoff.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return None.
*/
static inline void uart_ll_force_xoff(uart_port_t uart_num)
{
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE);
}
/**
* @brief Force UART xon.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return None.
*/
static inline void uart_ll_force_xon(uart_port_t uart_num)
{
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
REG_SET_BIT(UART_ID_REG(uart_num), UART_UPDATE);
}
/**
* @brief Get UART final state machine status.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return UART module FSM status.
*/
static inline uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
{
return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,174 @@
// 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.
// The LL layer for UHCI register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#include <stdio.h>
#include "uhci_types.h"
#include "soc/uhci_struct.h"
#include "soc/gdma_struct.h"
#define UHCI_DMA_INDEX 0
#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL))
static inline void uhci_ll_init(uhci_dev_t *hw)
{
typeof(hw->conf0) conf0_reg;
hw->conf0.clk_en = 1;
conf0_reg.val = 0;
conf0_reg.clk_en = 1;
hw->conf0.val = conf0_reg.val;
hw->conf1.val = 0;
}
static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num)
{
abort(); // TODO ESP32-C3 IDF-2117
}
static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char)
{
if (seper_char->sub_chr_en) {
typeof(hw->esc_conf0) esc_conf0_reg = hw->esc_conf0;
esc_conf0_reg.seper_char = seper_char->seper_chr;
esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1;
esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2;
hw->esc_conf0.val = esc_conf0_reg.val;
hw->escape_conf.tx_c0_esc_en = 1;
hw->escape_conf.rx_c0_esc_en = 1;
} else {
hw->escape_conf.tx_c0_esc_en = 0;
hw->escape_conf.rx_c0_esc_en = 0;
}
}
static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr)
{
(void)hw;
(void)seper_chr;
}
static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr)
{
typeof(hw->escape_conf) escape_conf_reg = hw->escape_conf;
if (sub_ctr->flow_en == 1) {
typeof(hw->esc_conf2) esc_conf2_reg = hw->esc_conf2;
typeof(hw->esc_conf3) esc_conf3_reg = hw->esc_conf3;
esc_conf2_reg.seq1 = sub_ctr->xon_chr;
esc_conf2_reg.seq1_char0 = sub_ctr->xon_sub1;
esc_conf2_reg.seq1_char1 = sub_ctr->xon_sub2;
esc_conf3_reg.seq2 = sub_ctr->xoff_chr;
esc_conf3_reg.seq2_char0 = sub_ctr->xoff_sub1;
esc_conf3_reg.seq2_char1 = sub_ctr->xoff_sub2;
escape_conf_reg.tx_11_esc_en = 1;
escape_conf_reg.tx_13_esc_en = 1;
escape_conf_reg.rx_11_esc_en = 1;
escape_conf_reg.rx_13_esc_en = 1;
hw->esc_conf2.val = esc_conf2_reg.val;
hw->esc_conf3.val = esc_conf3_reg.val;
} else {
escape_conf_reg.tx_11_esc_en = 0;
escape_conf_reg.tx_13_esc_en = 0;
escape_conf_reg.rx_11_esc_en = 0;
escape_conf_reg.rx_13_esc_en = 0;
}
hw->escape_conf.val = escape_conf_reg.val;
}
static inline void uhci_ll_dma_in_reset(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].in.in_conf0.in_rst = 1;
GDMA.channel[UHCI_DMA_INDEX].in.in_conf0.in_rst = 0;
}
static inline void uhci_ll_dma_out_reset(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].out.out_conf0.out_rst = 1;
GDMA.channel[UHCI_DMA_INDEX].out.out_conf0.out_rst = 0;
}
static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val |= intr_mask;
}
static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_ena.val &= (~intr_mask);
}
static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask)
{
hw->int_clr.val = intr_mask;
}
static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw)
{
return hw->int_st.val;
}
static inline void uhci_ll_set_rx_dma(uhci_dev_t *hw, uint32_t addr)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].in.in_link.addr = addr;
}
static inline void uhci_ll_set_tx_dma(uhci_dev_t *hw, uint32_t addr)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].out.out_link.addr = addr;
}
static inline void uhci_ll_rx_dma_start(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].in.in_link.start = 1;
}
static inline void uhci_ll_tx_dma_start(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].out.out_link.start = 1;
}
static inline void uhci_ll_rx_dma_stop(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].in.in_link.stop = 1;
}
static inline void uhci_ll_tx_dma_stop(uhci_dev_t *hw)
{
(void)hw;
GDMA.channel[UHCI_DMA_INDEX].out.out_link.stop = 1;
}
static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode)
{
if (eof_mode & UHCI_RX_BREAK_CHR_EOF) {
hw->conf0.uart_rx_brk_eof_en = 1;
}
if (eof_mode & UHCI_RX_IDLE_EOF) {
hw->conf0.uart_idle_eof_en = 1;
}
if (eof_mode & UHCI_RX_LEN_EOF) {
hw->conf0.len_eof_en = 1;
}
}

View File

@ -0,0 +1,383 @@
#pragma once
#include "soc/soc_caps.h"
#include "hal/adc_types.h"
#include "hal/adc_ll.h"
#include "esp_err.h"
#if CONFIG_IDF_TARGET_ESP32C3
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#include "hal/dma_types.h"
#include "hal/adc_ll.h"
#include "hal/dma_types.h"
#include "esp_err.h"
//For ADC module, each conversion contains 4 bytes
#define ADC_HAL_DATA_LEN_PER_CONV 4
/**
* @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 {
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 */
gdma_dev_t *dev; ///< GDMA address
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*/
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;
#endif
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* ADC module initialization.
*/
void adc_hal_init(void);
/**
* Set ADC module power management.
*
* @prarm manage Set ADC power status.
*/
#define adc_hal_set_power_manage(manage) adc_ll_set_power_manage(manage)
/**
* ADC module clock division factor setting. ADC clock devided from APB clock.
*
* @prarm div Division factor.
*/
#define adc_hal_digi_set_clk_div(div) adc_ll_digi_set_clk_div(div)
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* ADC SAR clock division factor setting. ADC SAR clock devided from `RTC_FAST_CLK`.
*
* @prarm div Division factor.
*/
#define adc_hal_set_sar_clk_div(adc_n, div) adc_ll_set_sar_clk_div(adc_n, div)
/**
* 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.
*
* @prarm adc_n ADC unit.
* @prarm ctrl ADC controller.
*/
#define adc_hal_set_controller(adc_n, ctrl) adc_ll_set_controller(adc_n, ctrl)
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/**
* Get the attenuation of a particular channel on ADCn.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @return atten The attenuation option.
*/
#define adc_hal_get_atten(adc_n, channel) adc_ll_get_atten(adc_n, channel)
#endif
#if CONFIG_IDF_TARGET_ESP32
/**
* Close ADC AMP module if don't use it for power save.
*/
#define adc_hal_amp_disable() adc_ll_amp_disable()
#endif
/*---------------------------------------------------------------
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()
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* 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)
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
/**
* 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
---------------------------------------------------------------*/
/**
* Digital controller deinitialization.
*/
void adc_hal_digi_deinit(void);
/**
* Setting the digital controller.
*
* @param cfg Pointer to digital controller paramter.
*/
void adc_hal_digi_controller_config(const adc_digi_config_t *cfg);
/**
* Reset the pattern table pointer, then take the measurement rule from table header in next measurement.
*
* @param adc_n ADC unit.
*/
#define adc_hal_digi_clear_pattern_table(adc_n) adc_ll_digi_clear_pattern_table(adc_n)
/*---------------------------------------------------------------
ADC Single Read
---------------------------------------------------------------*/
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* 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 // CONFIG_IDF_TARGET_ESP32C3
/**
* 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
/**
* 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_HW_CALIBRATION_V1
// ESP32-S2 and C3 support HW offset calibration.
/**
* @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_HW_CALIBRATION_V1
#if CONFIG_IDF_TARGET_ESP32C3
/*---------------------------------------------------------------
DMA setting
---------------------------------------------------------------*/
/**
* @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);
/**
* @brief Reset ADC / DMA fifo
*
* @param hal Context of the HAL
*/
void adc_hal_fifo_reset(adc_hal_context_t *hal);
/**
* @brief Start DMA
*
* @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_rxdma_start(adc_hal_context_t *hal, uint8_t *data_buf);
/**
* @brief Start ADC
*
* @param hal Context of the HAL
*/
void adc_hal_digi_start(adc_hal_context_t *hal);
/**
* @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 Stop DMA
*
* @param hal Context of the HAL
*/
void adc_hal_digi_rxdma_stop(adc_hal_context_t *hal);
/**
* @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 ADC
*
* @param hal Context of the HAL
*/
void adc_hal_digi_stop(adc_hal_context_t *hal);
#endif //#if CONFIG_IDF_TARGET_ESP32C3

View File

@ -0,0 +1,441 @@
// 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 <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 to up to approx. 1100 mV. */
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 1350 mV. */
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 2600 mV. */
ADC_ATTEN_MAX,
} adc_atten_t;
#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;
/**
* @brief ADC resolution setting option.
*
*/
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.
*
* @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_CONV_SINGLE_UNIT_1 = 1, /*!< SAR ADC 1. */
ADC_CONV_SINGLE_UNIT_2 = 2, /*!< SAR ADC 2. */
ADC_CONV_BOTH_UNIT = 3, /*!< SAR ADC 1 and 2. */
ADC_CONV_ALTER_UNIT = 7, /*!< SAR ADC 1 and 2 alternative mode. */
ADC_CONV_UNIT_MAX,
} adc_digi_convert_mode_t;
/**
* @brief ADC digital controller (DMA mode) conversion rules setting.
*/
typedef struct {
union {
struct {
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
0: measurement range 0 - 800mV,
1: measurement range 0 - 1100mV,
2: measurement range 0 - 1350mV,
3: measurement range 0 - 2600mV. */
#if CONFIG_IDF_TARGET_ESP32
uint8_t bit_width: 2; /*!< ADC resolution.
- 0: 9 bit;
- 1: 10 bit;
- 2: 11 bit;
- 3: 12 bit. */
int8_t channel: 4; /*!< ADC channel index. */
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
uint8_t reserved: 2; /*!< reserved0 */
uint8_t channel: 4; /*!< ADC channel index. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint8_t channel: 3; /*!< ADC channel index. */
uint8_t unit: 1; /*!< ADC unit index. */
uint8_t reserved: 2; /*!< reserved0 */
#endif
};
uint8_t val; /*!<Raw data value */
};
} adc_digi_pattern_table_t;
/**
* @brief ADC digital controller (DMA mode) output data format option.
*/
typedef enum {
ADC_DIGI_FORMAT_12BIT, /*!<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, /*!<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,
} adc_digi_output_format_t;
#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-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. For ESP32-S2:
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
} type1; /*!<When the configured output format is 12bit. `ADC_DIGI_FORMAT_12BIT` */
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;
#endif
#if CONFIG_IDF_TARGET_ESP32C3
/**
* @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;
#endif
#if !CONFIG_IDF_TARGET_ESP32
/**
* @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 //!CONFIG_IDF_TARGET_ESP32
/**
* @brief ADC digital controller (DMA mode) configuration parameters.
*
* Example setting: When using ADC1 channel0 to measure voltage, the sampling rate is required to be 1 kHz:
*
* +---------------------+--------+--------+--------+
* | sample rate | 1 kHz | 1 kHz | 1 kHz |
* +---------------------+--------+--------+--------+
* | conv_mode | single | both | alter |
* | adc1_pattern_len | 1 | 1 | 1 |
* | dig_clk.use_apll | 0 | 0 | 0 |
* | dig_clk.div_num | 99 | 99 | 99 |
* | dig_clk.div_b | 0 | 0 | 0 |
* | dig_clk.div_a | 0 | 0 | 0 |
* | interval | 400 | 400 | 200 |
* +---------------------+--------+--------+--------+
* | `trigger_meas_freq` | 1 kHz | 1 kHz | 2 kHz |
* +---------------------+--------+--------+--------+
*
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
*
* +---------------------+--------+--------+--------+
* | conv_mode | single | both | alter |
* +---------------------+--------+--------+--------+
* | trigger meas times | 1 | 1 | 1 |
* +---------------------+--------+--------+--------+
* | conv_limit_num | +1 | +1 | +1 |
* | dma_eof_num | +1 | +2 | +1 |
* | dma output (byte) | +2 | +4 | +2 |
* +---------------------+--------+--------+--------+
*/
typedef struct {
bool conv_limit_en; /*!<Enable the function of limiting ADC conversion times.
If the number of ADC conversion trigger count is equal to the `limit_num`, the conversion is stopped. */
uint32_t conv_limit_num; /*!<Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. */
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
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. */
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
adc_digi_output_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_output_format_t``. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint32_t adc_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 7 (0: Don't change the pattern table setting).
The pattern table that defines the conversion rules for each SAR ADC. Each table has 7 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. */
adc_digi_pattern_table_t *adc_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc_pattern_len`. */
#endif
#if CONFIG_IDF_TARGET_ESP32S2
uint32_t interval; /*!<The number of interval clock cycles for the digital controller to trigger the measurement.
The unit is the divided clock. Range: 40 ~ 4095.
Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. Refer to ``adc_digi_clk_t``.
Note: The sampling rate of each channel is also related to the conversion mode (See ``adc_digi_convert_mode_t``) and pattern table settings. */
adc_digi_clk_t dig_clk; /*!<ADC 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. */
uint32_t dma_eof_num; /*!<DMA eof num of adc digital controller.
If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated in DMA.
Note: The converted data in the DMA in link buffer will be multiple of two bytes. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Range: 611Hz ~ 83333Hz
Fs = Fd / interval / 2
Fs: sampling frequency;
Fd: digital controller frequency, no larger than 5M for better performance
interval: interval between 2 measurement trigger signal, the smallest interval should not be smaller than the ADC measurement period, the largest interval should not be larger than 4095 */
#endif
} adc_digi_config_t;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/**
* @brief ADC digital controller (DMA mode) interrupt type options.
*/
typedef enum {
ADC_DIGI_INTR_MASK_MONITOR = 0x1,
ADC_DIGI_INTR_MASK_MEAS_DONE = 0x2,
ADC_DIGI_INTR_MASK_ALL = 0x3,
} adc_digi_intr_t;
FLAG_ATTR(adc_digi_intr_t)
#endif
#if !CONFIG_IDF_TARGET_ESP32
/**
* @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, \
}
/**
* @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
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;
/**
* @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
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
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 // CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3

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,132 @@
// 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_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,80 @@
// 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"
#include "hal/hal_defs.h"
#include <esp_err.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,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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @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 */

View File

@ -0,0 +1,112 @@
// 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 Check whether the key input (HMAC on ESP32-C3) is correct.
*/
ds_key_check_t ds_hal_check_decryption_key(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,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,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,471 @@
// 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
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,371 @@
// 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 */
#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
#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 mode only */
GPIO_NUM_47 = 47, /*!< GPIO47, 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_22 = 22, /*!< GPIO22, 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,30 @@
// Copyright 2010-2018 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_log.h"
// platform related stuff
#define HAL_SWAP32(word) __builtin_bswap32(word)
#define HAL_SWAP64(word) __builtin_bswap64(word)
#define HAL_LOGE(...) ESP_LOGE(__VA_ARGS__)
#define HAL_LOGW(...) ESP_LOGW(__VA_ARGS__)
#define HAL_LOGI(...) ESP_LOGI(__VA_ARGS__)
#define HAL_LOGD(...) ESP_LOGD(__VA_ARGS__)
#define HAL_LOGV(...) ESP_LOGV(__VA_ARGS__)
#define STATIC_HAL_REG_CHECK(TAG, ENUM, VAL) _Static_assert((ENUM) == (VAL), #TAG" "#ENUM" definition no longer matches register value")

View File

@ -0,0 +1,534 @@
// 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 trasaction
*
* @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 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,124 @@
// 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;
// I2C clk flags for users to use, can be expanded in the future.
#define I2C_SCLK_SRC_FLAG_FOR_NOMAL (0) /*!< Any one clock source that is available for the specified frequency may be choosen*/
#define I2C_SCLK_SRC_FLAG_AWARE_DFS (1 << 0) /*!< For REF tick clock, it won't change with APB.*/
#define I2C_SCLK_SRC_FLAG_LIGHT_SLEEP (1 << 1) /*!< For light sleep mode.*/
/// Use the highest speed that is available for the clock source picked by clk_flags
#define I2C_CLK_FREQ_MAX (-1)
/**
* @brief I2C initialization parameters
*/
typedef struct{
i2c_mode_t mode; /*!< I2C mode */
int sda_io_num; /*!< GPIO number for I2C sda signal */
int scl_io_num; /*!< GPIO number for I2C scl signal */
bool sda_pullup_en; /*!< Internal GPIO pull mode for I2C sda signal*/
bool scl_pullup_en; /*!< Internal GPIO pull mode for I2C scl signal*/
union {
struct {
uint32_t clk_speed; /*!< I2C clock frequency for master mode, (no higher than 1MHz for now) */
} master; /*!< I2C master config */
struct {
uint8_t addr_10bit_en; /*!< I2C 10bit address mode enable for slave mode */
uint16_t slave_addr; /*!< I2C address for slave mode */
} slave; /*!< I2C slave config */
};
uint32_t clk_flags; /*!< Bitwise of ``I2C_SCLK_SRC_FLAG_**FOR_DFS**`` for clk source choice*/
} i2c_config_t;
#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,300 @@
// 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 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_ll.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* 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 Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param status interrupt status
*/
#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status)
/**
* @brief Clear I2S interrupt status
*
* @param hal Context of the HAL layer
* @param mask interrupt status mask
*/
#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Get I2S out eof des address
*
* @param hal Context of the HAL layer
* @param addr out eof des address
*/
#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr)
/**
* @brief Get I2S in eof des address
*
* @param hal Context of the HAL layer
* @param addr in eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr)
/**
* @brief Enable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev)
/**
* @brief Disable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev)
/**
* @brief Disable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev)
/**
* @brief Enable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev)
/**
* @brief Set I2S tx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S in link
*
* @param hal Context of the HAL layer
* @param rx_eof_num in link eof num
* @param addr in link address
*/
void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t rx_eof_num, uint32_t addr);
/**
* @brief Set I2S clk div
*
* @param hal Context of the HAL layer
* @param div_num i2s clkm div num
* @param div_a i2s clkm div a
* @param div_b i2s clkm div b
* @param tx_bck_div tx bck div num
* @param rx_bck_div rx bck div num
*/
void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div);
/**
* @brief Set I2S clock sel
*
* @param hal Context of the HAL layer
* @param sel clock sel
*/
#define i2s_hal_set_clock_sel(hal, sel) i2s_ll_set_clk_sel((hal)->dev, sel)
/**
* @brief Set I2S tx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Reset I2S TX & RX module, including DMA and FIFO
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset(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 Config I2S param
*
* @param hal Context of the HAL layer
* @param i2s_config I2S configurations - see i2s_config_t struct
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config);
/**
* @brief Enable I2S sig loopback
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1)
/**
* @brief Enable I2S master mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal);
/**
* @brief Enable I2S slave mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal);
/**
* @brief Init the I2S hal and set the I2S 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 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);
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief Set I2S tx pdm
*
* @param hal Context of the HAL layer
* @param fp tx pdm fp
* @param fs tx pdm fs
*/
void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs);
/**
* @brief Get I2S tx pdm
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
*/
void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr);
/**
* @brief Get I2S tx pdm configuration
*
* @param hal Context of the HAL layer
* @param fp Pointer to receive tx PDM fp configuration
* @param fs Pointer to receive tx PDM fs configuration
*/
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs);
/**
* @brief Get I2S rx pdm configuration
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
*/
void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,204 @@
// 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
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
*/
typedef enum {
I2S_NUM_0 = 0, /*!< I2S port 0 */
#if SOC_I2S_NUM > 1
I2S_NUM_1 = 1, /*!< I2S port 1 */
#endif
I2S_NUM_MAX, /*!< I2S port max */
} i2s_port_t;
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
} i2s_channel_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
// In order to keep compatibility, remain the old definitions and introduce new definitions,
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X03, /*!< 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 = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*
*/
typedef enum {
I2S_MODE_MASTER = 1, /*!< Master mode*/
I2S_MODE_SLAVE = 2, /*!< Slave mode*/
I2S_MODE_TX = 4, /*!< TX mode*/
I2S_MODE_RX = 8, /*!< RX mode*/
#if SOC_I2S_SUPPORTS_ADC_DAC
I2S_MODE_DAC_BUILT_IN = 16, /*!< 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*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif
#if SOC_I2S_SUPPORTS_PDM
I2S_MODE_PDM = 64, /*!< PDM mode*/
#endif
} i2s_mode_t;
/**
* @brief I2S source clock
*
*/
typedef enum {
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
I2S_CLK_APLL, /*!< Clock from APLL*/
} i2s_clock_src_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
*
* @note PDM and 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;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_PDM
/**
* @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;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/
PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/
} pdm_pcm_conv_t;
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,207 @@
// 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 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 Disables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
* @return oldmask where to store old interrupts state
*/
static inline uint32_t interrupt_controller_hal_disable_int_mask(uint32_t newmask)
{
return intr_cntrl_ll_disable_int_mask(newmask);
}
/**
* @brief Enables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
*/
static inline void interrupt_controller_hal_enable_int_mask(uint32_t newmask)
{
intr_cntrl_ll_enable_int_mask(newmask);
}
/**
* @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,37 @@
// 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 soc/README.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/lcd_cam_struct.h"
typedef struct {
lcd_cam_dev_t *dev;
} lcd_hal_context_t;
void lcd_hal_init(lcd_hal_context_t *hal, int id);
#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,157 @@
// 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 <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;
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_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/
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_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 {
LEDC_REF_TICK = LEDC_USE_REF_TICK, /*!< LEDC timer clock divided from reference tick (1Mhz) */
LEDC_APB_CLK = LEDC_USE_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */
} 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;
/**
* @brief Configuration parameters of LEDC channel for ledc_channel_config function
*/
typedef struct {
int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
ledc_channel_t channel; /*!< LEDC channel (0 - 7) */
ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable */
ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - 3) */
uint32_t duty; /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */
int hpoint; /*!< LEDC channel hpoint value, the max value is 0xfffff */
} ledc_channel_config_t;
/**
* @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
*/
typedef struct {
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
union {
ledc_timer_bit_t duty_resolution; /*!< LEDC channel duty resolution */
ledc_timer_bit_t bit_num __attribute__((deprecated)); /*!< Deprecated in ESP-IDF 3.0. This is an alias to 'duty_resolution' for backward compatibility with ESP-IDF 2.1 */
};
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */
uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */
ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock.
For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK.
For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/
} ledc_timer_config_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,328 @@
// 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 MCPWM (common part)
/*
* MCPWM HAL usages:
*
* Initialization:
* 1. Fill the parameters in `mcpwm_hal_context_t`.
* 2. Call `mcpwm_hal_init` to initialize the context.
* 3. Call `mcpwm_hal_hw_init` to initialize the hardware.
*
* Basic PWM:
* 1. Update parameters for the timers, comparators and generators.
* 2. Call `mcpwm_hal_timer_update_basic` to update the timer used.
* 3. Call `mcpwm_hal_operator_update_basic` to update all the parameters of a operator.
*
* Alternatively, if only the comparator is updated (duty rate), call
* `mcpwm_hal_operator_update_comparator` to update the comparator parameters; if only the
* generator is updated (output style), call `mcpwm_hal_operator_update_generator` to update the
* generator parameters.
*
* 4. At any time, call `mcpwm_hal_timer_start` to start the timer (so that PWM output will toggle
* according to settings), or call `mcpwm_hal_timer_stop` to stop the timer (so that the PWM output
* will be kept as called).
*
* Timer settings:
* - Sync: Call `mcpwm_hal_timer_enable_sync` to enable the sync for the timer, and call
* `mcpwm_hal_timer_disable_sync` to disable it.
*
* Operator settings:
* - Carrier: Call `mcpwm_hal_operator_enable_carrier` to enable carrier for an operator, and call
* `mcpwm_hal_operator_disable_carrier` to disable it.
*
* - Deadzone: Call `mcpwm_hal_operator_update_deadzone` to update settings of deadzone for an operator.
*
* Fault handling settings:
* 1. Call `mcpwm_hal_fault_init` to initialize an fault signal to be detected.
* 2. Call `mcpwm_hal_operator_update_fault` to update the behavior of an operator when fault is
* detected.
* 3. If the operator selects oneshot mode to handle the fault event, call
* `mcpwm_hal_fault_oneshot_clear` to clear that fault event after the fault is handled properly.
* 4. Call `mcpwm_hal_fault_disable` to deinitialize the fault signal when it's no longer used.
*
* Capture:
* 1. Call `mcpwm_hal_capture_enable` to enable the capture for one capture signal.
* 2. Call `mcpwm_hal_capture_get_result` to get the last captured result.
* 3. Call `mcpwm_hal_capture_disable` to disable the capture for a signal.
*/
#pragma once
#include <esp_err.h>
#include "hal/mcpwm_ll.h"
#define MCPWM_BASE_CLK (2 * APB_CLK_FREQ) //2*APB_CLK_FREQ 160Mhz
/// Configuration of HAL that used only once.
typedef struct {
int host_id; ///< Which MCPWM peripheral to use, 0-1.
} mcpwm_hal_init_config_t;
/// Configuration of each generator (output of operator)
typedef struct {
mcpwm_duty_type_t duty_type; ///< How the generator output
int comparator; ///< for mode `MCPWM_DUTY_MODE_*`, which comparator it refers to.
} mcpwm_hal_generator_config_t;
/// Configuration of each operator
typedef struct {
mcpwm_hal_generator_config_t gen[SOC_MCPWM_GENERATORS_PER_OPERATOR]; ///< Configuration of the generators
float duty[SOC_MCPWM_COMPARATORS_PER_OPERATOR]; ///< Duty rate for each comparator, 10 means 10%.
int timer; ///< The timer this operator is using
} mcpwm_hal_operator_config_t;
/// Configuration of each timer
typedef struct {
uint32_t timer_prescale; ///< The prescale from the MCPWM main clock to the timer clock, TIMER_FREQ=(MCPWM_FREQ/(timer_prescale+1))
uint32_t freq; ///< Frequency desired, will be updated to actual value after the `mcpwm_hal_timer_update_freq` is called.
mcpwm_counter_type_t count_mode; ///< Counting mode
} mcpwm_hal_timer_config_t;
typedef struct {
mcpwm_dev_t *dev; ///< Beginning address of the MCPWM peripheral registers. Call `mcpwm_hal_init` to initialize it.
uint32_t prescale; ///< Prescale from the 160M clock to MCPWM main clock.
mcpwm_hal_timer_config_t timer[SOC_MCPWM_TIMERS_PER_GROUP]; ///< Configuration of the timers
mcpwm_hal_operator_config_t op[SOC_MCPWM_OPERATORS_PER_GROUP]; ///< Configuration of the operators
} mcpwm_hal_context_t;
/// Configuration of the carrier
typedef struct {
bool inverted; ///< Whether to invert the output
uint8_t duty; ///< Duty of the carrier, 0-7. Duty rate = duty/8.
uint8_t oneshot_pulse_width; ///< oneshot pulse width, in carrier periods. 0 to disable. 0-15.
uint32_t period; ///< Prescale from the MCPWM main clock to the carrier clock. CARRIER_FREQ=(MCPWM_FREQ/(period+1)/8.)
} mcpwm_hal_carrier_conf_t;
/// Configuration of the deadzone
typedef struct {
mcpwm_deadtime_type_t mode; ///< Deadzone mode, `MCPWM_DEADTIME_BYPASS` to disable.
uint32_t fed; ///< Delay on falling edge. By MCPWM main clock.
uint32_t red; ///< Delay on rising edge. By MCPWM main clock.
} mcpwm_hal_deadzone_conf_t;
/// Configuration of the fault handling for each operator
typedef struct {
uint32_t cbc_enabled_mask; ///< Whether the cycle-by-cycle fault handling is enabled on each fault signal. BIT(n) stands for signal n.
uint32_t ost_enabled_mask; ///< Whether the oneshot fault handling is enabled on each on each fault signal. BIT(n) stands for signal n.
mcpwm_output_action_t action_on_fault[SOC_MCPWM_GENERATORS_PER_OPERATOR]; ///< Action to perform on each generator when any one of the fault signal triggers.
} mcpwm_hal_fault_conf_t;
/// Configuration of the synchronization of each clock
typedef struct {
mcpwm_sync_signal_t sync_sig; ///< Sync signal to use
uint32_t reload_permillage; ///< Reload permillage when the sync is triggered. 100 means the timer will be reload to (period * 100)/1000=10% period value.
} mcpwm_hal_sync_config_t;
/// Configuration of the capture feature on each capture signal
typedef struct {
mcpwm_capture_on_edge_t cap_edge; ///< Whether the edges is captured, bitwise.
uint32_t prescale; ///< Prescale of the input signal.
} mcpwm_hal_capture_config_t;
/**
* @brief Initialize the internal state of the HAL. Call after settings are set and before other functions are called.
*
* @note Since There are several individual parts (timers + operators, captures), this funciton is
* allowed to called several times.
*
* @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);
/**
* @brief Initialize the hardware, call after `mcpwm_hal_init` and before other functions.
*
* @param hal Context of the HAL layer.
*/
void mcpwm_hal_hw_init(mcpwm_hal_context_t *hal);
/**
* @brief Start a timer
*
* @param hal Context of the HAL layer.
* @param timer Timer to start, 0-2.
*/
void mcpwm_hal_timer_start(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Stop a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to stop, 0-2.
*/
void mcpwm_hal_timer_stop(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Update the basic parameters of a timer.
*
* @note This will influence the duty rate and count mode of each operator relies on this timer.
* Call `mcpwm_hal_operator_update_basic` for each of the operator that relies on this timer after
* to update the duty rate and generator output.
*
* @param hal Context of the HAL layer.
* @param timer Timer to update, 0-2.
*/
void mcpwm_hal_timer_update_basic(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Start the synchronization for a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to enable, 0-2.
* @param sync_conf Configuration of the sync operation.
*/
void mcpwm_hal_timer_enable_sync(mcpwm_hal_context_t *hal, int timer, const mcpwm_hal_sync_config_t *sync_conf);
/**
* @brief Stop the synchronization for a timer.
*
* @param hal Context of the HAL layer.
* @param timer Timer to disable sync, 0-2.
*/
void mcpwm_hal_timer_disable_sync(mcpwm_hal_context_t *hal, int timer);
/**
* @brief Update the basic settings (duty, output mode) for an operator.
*
* Will call `mcpwm_hal_operator_update_comparator` and `mcpwm_hal_operator_update_generator`
* recursively to update each of their duty and output mode.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
*/
void mcpwm_hal_operator_update_basic(mcpwm_hal_context_t *hal, int op);
/**
* @brief Update a comparator (duty) for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
* @param cmp Comparator to update, 0-1.
*/
void mcpwm_hal_operator_update_comparator(mcpwm_hal_context_t *hal, int op, int cmp);
/**
* @brief Update a generator (output mode) for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update, 0-2.
* @param cmp Comparator to update, 0-1.
*/
void mcpwm_hal_operator_update_generator(mcpwm_hal_context_t *hal, int op, int gen_num);
/**
* @brief Enable the carrier for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to enable carrier, 0-2.
* @param carrier_conf Configuration of the carrier.
*/
void mcpwm_hal_operator_enable_carrier(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_carrier_conf_t *carrier_conf);
/**
* @brief Disable the carrier for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to disable carrier, 0-2.
*/
void mcpwm_hal_operator_disable_carrier(mcpwm_hal_context_t *hal, int op);
/**
* @brief Update the deadzone for an operator.
*
* @param hal Context of the HAL layer.
* @param op Operator to update the deadzone, 0-2.
* @param deadzone Configuration of the deadzone. Set member `mode` to `MCPWM_DEADTIME_BYPASS` will bypass the deadzone.
*/
void mcpwm_hal_operator_update_deadzone(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_deadzone_conf_t *deadzone);
/**
* @brief Enable one of the fault signal.
*
* @param hal Context of the HAL layer.
* @param fault_sig The signal to enable, 0-2.
* @param level The active level for the fault signal, true for high and false for low.
*/
void mcpwm_hal_fault_init(mcpwm_hal_context_t *hal, int fault_sig, bool level);
/**
* @brief Configure how the operator behave to the fault signals.
*
* Call after the fault signal is enabled by `mcpwm_hal_fault_init`.
*
* @param hal Context of the HAL layer.
* @param op Operator to configure, 0-2.
* @param fault_conf Configuration of the behavior of the operator when fault. Clear member `cbc_enabled_mask` and `ost_enabled_mask` will disable the fault detection of this operator.
*/
void mcpwm_hal_operator_update_fault(mcpwm_hal_context_t *hal, int op, const mcpwm_hal_fault_conf_t *fault_conf);
/**
* @brief Clear the oneshot fault status for an operator.
*
* @param hal Context of the HAL layer.
* @param op The operator to clear oneshot fault status, 0-2.
*/
void mcpwm_hal_fault_oneshot_clear(mcpwm_hal_context_t *hal, int op);
/**
* @brief Disable one of the fault signal.
*
* @param hal Context of the HAL layer.
* @param fault_sig The fault signal to disable, 0-2.
*/
void mcpwm_hal_fault_disable(mcpwm_hal_context_t *hal, int fault_sig);
/**
* @brief Enable one of the capture signal.
*
* @param hal Context of the HAL layer.
* @param cap_sig Capture signal to enable, 0-2.
* @param conf Configuration on how to capture the signal.
*/
void mcpwm_hal_capture_enable(mcpwm_hal_context_t *hal, int cap_sig, const mcpwm_hal_capture_config_t *conf);
/**
* @brief Get the capture result.
*
* @note The output value will always be updated with the register value, no matter event triggered or not.
*
* @param hal Context of the HAL layer.
* @param cap_sig Signal to get capture result, 0-2.
* @param out_count Output of the captured counter.
* @param out_edge Output of the captured edge.
* @return
* - ESP_OK: if a signal is captured
* - ESP_ERR_NOT_FOUND: if no capture event happened.
*/
esp_err_t mcpwm_hal_capture_get_result(mcpwm_hal_context_t *hal, int cap_sig, uint32_t *out_count,
mcpwm_capture_on_edge_t *out_edge);
/**
* @brief Disable one of the capture signal.
*
* @param hal Context of the HAL layer.
* @param cap_sig The signal to capture, 0-2.
*/
void mcpwm_hal_capture_disable(mcpwm_hal_context_t *hal, int cap_sig);

View File

@ -0,0 +1,87 @@
// 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
/// Interrupts for MCPWM
typedef enum {
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened
} mcpwm_intr_t;
/**
* @brief Select type of MCPWM counter
*/
typedef enum {
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
} mcpwm_counter_type_t;
/**
* @brief Select type of MCPWM duty cycle mode
*/
typedef enum {
MCPWM_DUTY_MODE_0 = 0, /*!<Active high duty, i.e. duty cycle proportional to high time for asymmetric MCPWM*/
MCPWM_DUTY_MODE_1, /*!<Active low duty, i.e. duty cycle proportional to low time for asymmetric MCPWM, out of phase(inverted) MCPWM*/
MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH,
MCPWM_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/
} mcpwm_duty_type_t;
/**
* @brief MCPWM select action to be taken on the output when event happens
*/
typedef enum {
MCPWM_ACTION_NO_CHANGE = 0, /*!<No change in the output*/
MCPWM_ACTION_FORCE_LOW, /*!<Make output low*/
MCPWM_ACTION_FORCE_HIGH, /*!<Make output high*/
MCPWM_ACTION_TOGGLE, /*!<Make output toggle*/
} mcpwm_output_action_t;
/**
* @brief MCPWM deadtime types, used to generate deadtime, RED refers to rising edge delay and FED refers to falling edge delay
*/
typedef enum {
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = compliment of falling edge delay*/
MCPWM_ACTIVE_LOW_COMPLIMENT_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = falling edge delay*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXA*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXB, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXB*/
MCPWM_DEADTIME_TYPE_MAX,
} mcpwm_deadtime_type_t;
/**
* @brief MCPWM select sync signal input
*/
typedef enum {
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/
} mcpwm_sync_signal_t;
/**
* @brief MCPWM select capture starts from which edge
*/
typedef enum {
MCPWM_NEG_EDGE = BIT(0), /*!<Capture the negative edge*/
MCPWM_POS_EDGE = BIT(1), /*!<Capture the positive edge*/
MCPWM_BOTH_EDGE = BIT(1)|BIT(0), /*!<Capture both edges*/
} mcpwm_capture_on_edge_t;

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,223 @@
// 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 <stdio.h>
#include "soc/pcnt_periph.h"
#include "hal/pcnt_types.h"
#include "hal/pcnt_ll.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_hal_context_t;
/**
* @brief Set PCNT counter mode
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pos_mode Counter mode when detecting positive edge
* @param neg_mode Counter mode when detecting negative edge
* @param hctrl_mode Counter mode when control signal is high level
* @param lctrl_mode Counter mode when control signal is low level
*/
#define pcnt_hal_set_mode(hal, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode) pcnt_ll_set_mode((hal)->dev, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode)
/**
* @brief Get pulse counter value
*
* @param hal Context of the HAL layer
* @param unit Pulse Counter unit number
* @param count Pointer to accept counter value
*/
#define pcnt_hal_get_counter_value(hal, unit, count) pcnt_ll_get_counter_value((hal)->dev, unit, count)
/**
* @brief Pause PCNT counter of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_counter_pause(hal, unit) pcnt_ll_counter_pause((hal)->dev, unit)
/**
* @brief Resume counting for PCNT counter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number, select from unit_t
*/
#define pcnt_hal_counter_resume(hal, unit) pcnt_ll_counter_resume((hal)->dev, unit)
/**
* @brief Clear and reset PCNT counter value to zero
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number, select from unit_t
*/
#define pcnt_hal_counter_clear(hal, unit) pcnt_ll_counter_clear((hal)->dev, unit)
/**
* @brief Enable PCNT interrupt for PCNT unit
* @note
* Each Pulse counter unit has five watch point events that share the same interrupt.
* Configure events with pcnt_event_enable() and pcnt_event_disable()
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_intr_enable(hal, unit) pcnt_ll_intr_enable((hal)->dev, unit)
/**
* @brief Disable PCNT interrupt for PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_intr_disable(hal, unit) pcnt_ll_intr_disable((hal)->dev, unit)
/**
* @brief Get PCNT interrupt status
*
* @param hal Context of the HAL layer
* @param mask The interrupt status mask to be cleared. Pointer to accept value interrupt status mask.
*/
#define pcnt_hal_get_intr_status(hal, mask) pcnt_ll_get_intr_status((hal)->dev, mask)
/**
* @brief Clear PCNT interrupt status
*
* @param hal Context of the HAL layer
* @param mask The interrupt status mask to be cleared.
*/
#define pcnt_hal_clear_intr_status(hal, mask) pcnt_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Enable PCNT event of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*/
#define pcnt_hal_event_enable(hal, unit, evt_type) pcnt_ll_event_enable((hal)->dev, unit, evt_type)
/**
* @brief Disable PCNT event of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*/
#define pcnt_hal_event_disable(hal, unit, evt_type) pcnt_ll_event_disable((hal)->dev, unit, evt_type)
/**
* @brief Set PCNT event value of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*
* @param value Counter value for PCNT event
*/
#define pcnt_hal_set_event_value(hal, unit, evt_type, value) pcnt_ll_set_event_value((hal)->dev, unit, evt_type, value)
/**
* @brief Get PCNT event value of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
* @param value Pointer to accept counter value for PCNT event
*/
#define pcnt_hal_get_event_value(hal, unit, evt_type, value) pcnt_ll_get_event_value((hal)->dev, unit, evt_type, value)
/**
* @brief Get PCNT event status
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @return event status word
*/
#define pcnt_hal_get_event_status(hal, unit) pcnt_ll_get_event_status((hal)->dev, unit)
/**
* @brief Set PCNT filter value
*
* @param hal Context of the HAL layer
* @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.
* @note
* filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
*/
#define pcnt_hal_set_filter_value(hal, unit, filter_val) pcnt_ll_set_filter_value((hal)->dev, unit, filter_val)
/**
* @brief Get PCNT filter value
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param filter_val Pointer to accept PCNT filter value.
*/
#define pcnt_hal_get_filter_value(hal, unit, filter_val) pcnt_ll_get_filter_value((hal)->dev, unit, filter_val)
/**
* @brief Enable PCNT input filter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_filter_enable(hal, unit) pcnt_ll_filter_enable((hal)->dev, unit)
/**
* @brief Disable PCNT input filter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_filter_disable(hal, unit) pcnt_ll_filter_disable((hal)->dev, unit)
/**
* @brief Init the PCNT hal and set the PCNT 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 pcnt_num The uart port number, the max port number is (PCNT_NUM_MAX -1)
*/
void pcnt_hal_init(pcnt_hal_context_t *hal, int pcnt_num);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,111 @@
// 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 "soc/soc_caps.h"
#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
/**
* @brief PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
*/
typedef enum {
PCNT_PORT_0 = 0, /*!< PCNT port 0 */
PCNT_PORT_MAX, /*!< PCNT port max */
} pcnt_port_t;
/**
* @brief Selection of all available PCNT units
*/
typedef enum {
PCNT_UNIT_0 = 0, /*!< PCNT unit 0 */
PCNT_UNIT_1 = 1, /*!< PCNT unit 1 */
PCNT_UNIT_2 = 2, /*!< PCNT unit 2 */
PCNT_UNIT_3 = 3, /*!< PCNT unit 3 */
#if SOC_PCNT_UNIT_NUM > 4
PCNT_UNIT_4 = 4, /*!< PCNT unit 4 */
PCNT_UNIT_5 = 5, /*!< PCNT unit 5 */
PCNT_UNIT_6 = 6, /*!< PCNT unit 6 */
PCNT_UNIT_7 = 7, /*!< PCNT unit 7 */
#endif
PCNT_UNIT_MAX,
} pcnt_unit_t;
/**
* @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO
* @note Configuration covers two actions, one for high, and one for low level on the control input
*/
typedef enum {
PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
PCNT_MODE_MAX
} pcnt_ctrl_mode_t;
/**
* @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO
* @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input
*/
typedef enum {
PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */
PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */
PCNT_COUNT_MAX
} pcnt_count_mode_t;
/**
* @brief Selection of channels available for a single PCNT unit
*/
typedef enum {
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */
PCNT_CHANNEL_MAX,
} pcnt_channel_t;
/**
* @brief Selection of counter's events the may trigger an interrupt
*/
typedef enum {
PCNT_EVT_THRES_1 = BIT(2), /*!< PCNT watch point event: threshold1 value event */
PCNT_EVT_THRES_0 = BIT(3), /*!< PCNT watch point event: threshold0 value event */
PCNT_EVT_L_LIM = BIT(4), /*!< PCNT watch point event: Minimum counter value */
PCNT_EVT_H_LIM = BIT(5), /*!< PCNT watch point event: Maximum counter value */
PCNT_EVT_ZERO = BIT(6), /*!< PCNT watch point event: counter value zero event */
PCNT_EVT_MAX
} pcnt_evt_type_t;
/**
* @brief Pulse Counter configuration for a single channel
*/
typedef struct {
int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */
int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */
int16_t counter_h_lim; /*!< Maximum counter value */
int16_t counter_l_lim; /*!< Minimum counter value */
pcnt_unit_t unit; /*!< PCNT unit number */
pcnt_channel_t channel; /*!< the PCNT channel */
} pcnt_config_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
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
/**
* @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,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 "hal/gpio_types.h"
#include "hal/rtc_cntl_ll.h"
#if !CONFIG_IDF_TARGET_ESP32C3
#include "hal/rtc_io_ll.h"
#endif
#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);
void rtc_cntl_hal_enable_cpu_retention(void *addr);
#define rtc_cntl_hal_disable_cpu_retention() rtc_cntl_ll_disable_cpu_retention()
/*
* Enable wakeup from ULP coprocessor.
*/
#define rtc_hal_ulp_wakeup_enable() rtc_cntl_ll_ulp_wakeup_enable()

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
#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,41 @@
// 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"
typedef enum SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#endif
#ifdef __cplusplus
extern "C" {
#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,258 @@
// 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_layout.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 reserved1; ///< Reserved, set to 0.
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.
spi_flash_sus_cmd_conf sus_cfg; ///< To store suspend command/mask information.
} spi_flash_hal_context_t;
_Static_assert(sizeof(spi_flash_hal_context_t) == 36, "size of spi_flash_hal_context_t incorrect. Please check data compatibility with the ROM");
/// Configuration structure for the SPI driver.
typedef struct {
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 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.
uint32_t cs_hold; ///< CS hold time config used by the host
bool auto_sus_en; ///< Auto suspend feature enable bit 1: enable, 0: disable.
} 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,215 @@
// 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
} 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_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
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;
///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,269 @@
// 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"
/**
* 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_ll_io_mode_t io_mode; ///< IO mode of the master
} 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 HSPI (SPI2) and 2 for VSPI (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 host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
*/
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,64 @@
// 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 "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 {
SPI_EV_BUF_TX = BIT(0), ///< The buffer has sent data to master, Slave HD only
SPI_EV_BUF_RX = BIT(1), ///< The buffer has received data from master, Slave HD only
SPI_EV_SEND = BIT(2), ///< Slave has loaded some data to DMA, and master has received certain number of the data, the number is determined by master. Slave HD only
SPI_EV_RECV = BIT(3), ///< Slave has received certain number of data from master, the number is determined by master. Slave HD only.
SPI_EV_CMD9 = BIT(4), ///< Received CMD9 from master, Slave HD only
SPI_EV_CMDA = BIT(5), ///< Received CMDA from master, Slave HD only
SPI_EV_TRANS = BIT(6), ///< A transaction has done
} spi_event_t;
FLAG_ATTR(spi_event_t)
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
//alias for different chips
#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 || CONFIG_IDF_TARGET_ESP32S3
// 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
#elif CONFIG_IDF_TARGET_ESP32C3
/* No SPI3_host on C3 */
#define SPI_HOST SPI1_HOST
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI2_HOST
#endif
/** @endcond */

View File

@ -0,0 +1,92 @@
// 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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "hal/systimer_types.h"
/**
* @brief enable systimer counter
*/
void systimer_hal_enable_counter(systimer_counter_id_t counter_id);
/**
* @brief get current counter value
*/
uint64_t systimer_hal_get_counter_value(systimer_counter_id_t counter_id);
/**
* @brief get current time (in microseconds)
*/
uint64_t systimer_hal_get_time(systimer_counter_id_t counter_id);
/*
* @brief set alarm target value (used in one-shot mode)
*/
void systimer_hal_set_alarm_target(systimer_alarm_id_t alarm_id, uint64_t target);
/**
* @brief set alarm period value (used in period mode)
*/
void systimer_hal_set_alarm_period(systimer_alarm_id_t alarm_id, uint32_t period);
/**
* @brief get alarm time
*/
uint64_t systimer_hal_get_alarm_value(systimer_alarm_id_t alarm_id);
/**
* @brief enable alarm interrupt
*/
void systimer_hal_enable_alarm_int(systimer_alarm_id_t alarm_id);
/**
* @brief select alarm mode
*/
void systimer_hal_select_alarm_mode(systimer_alarm_id_t alarm_id, systimer_alarm_mode_t mode);
/**
* @brief update systimer step when apb clock gets changed
*/
void systimer_hal_on_apb_freq_update(uint32_t apb_ticks_per_us);
/**
* @brief move systimer counter value forward or backward
*/
void systimer_hal_counter_value_advance(systimer_counter_id_t counter_id, int64_t time_us);
/**
* @brief initialize systimer in HAL layer
*/
void systimer_hal_init(void);
/**
* @brief connect alarm unit to selected counter
*/
void systimer_hal_connect_alarm_counter(systimer_alarm_id_t alarm_id, systimer_counter_id_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(uint32_t counter_id, uint32_t cpu_id, bool can);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,74 @@
// 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
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "soc/soc_caps.h"
/*
* @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 */
};
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 counter ID
*
*/
typedef enum {
SYSTIMER_COUNTER_0, /*!< systimer counter 0 */
#if SOC_SYSTIMER_COUNTER_NUM > 1
SYSTIMER_COUNTER_1, /*!< systimer counter 1 */
#endif
} systimer_counter_id_t;
/**
* @brief systimer alarm ID
*
*/
typedef enum {
SYSTIMER_ALARM_0, /*!< systimer alarm 0 */
SYSTIMER_ALARM_1, /*!< systimer alarm 1 */
SYSTIMER_ALARM_2, /*!< systimer alarm 2 */
} systimer_alarm_id_t;
/**
* @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,330 @@
// 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 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,289 @@
// 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
#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. */
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. */
} 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 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_5KBITS() {.brp = 800, .tseg_1 = 15, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
#define TWAI_TIMING_CONFIG_10KBITS() {.brp = 400, .tseg_1 = 15, .tseg_2 = 8, .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,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 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 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

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
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
bool use_external_phy;
} usb_hal_context_t;
void usb_hal_init(usb_hal_context_t *usb);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,452 @@
// 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>
#define USB_CTRL_REQ_ATTR __attribute__((packed))
#define USB_DESC_ATTR __attribute__((packed))
/* -----------------------------------------------------------------------------
------------------------------- Common USB Types -------------------------------
----------------------------------------------------------------------------- */
// ----------------------------- Device Related --------------------------------
/**
* @brief Enumeration of USB PHY type
*/
typedef enum {
USB_PHY_INTERNAL = 0, /**< Use the chip's internal USB PHY */
USB_PHY_EXTERNAL, /**< Use an external USB PHY */
} usb_phy_t;
// ------------------------------ Bus Related ----------------------------------
/**
* @brief USB Standard Speeds
*/
typedef enum {
USB_SPEED_LOW = 0, /**< USB Low Speed (1.5 Mbit/s) */
USB_SPEED_FULL, /**< USB Full Speed (12 Mbit/s) */
} usb_speed_t;
// ---------------------------- Transfer Related -------------------------------
/**
* @brief The type of USB transfer
*
* @note The enum values need to match the bmAttributes field of an EP descriptor
*/
typedef enum {
USB_XFER_TYPE_CTRL = 0,
USB_XFER_TYPE_ISOCHRONOUS,
USB_XFER_TYPE_BULK,
USB_XFER_TYPE_INTR,
} usb_xfer_type_t;
/**
* @brief The status of a particular transfer
*/
typedef enum {
USB_TRANSFER_STATUS_COMPLETED, /**< The transfer was successful (but may be short) */
USB_TRANSFER_STATUS_ERROR, /**< The transfer failed because due to excessive errors (e.g. no response or CRC error) */
USB_TRANSFER_STATUS_TIMED_OUT, /**< The transfer failed due to to a time out */
USB_TRANSFER_STATUS_CANCELLED, /**< The transfer was cancelled */
USB_TRANSFER_STATUS_STALL, /**< The transfer was stalled */
USB_TRANSFER_STATUS_NO_DEVICE, /**< The transfer failed because the device is no longer valid (e.g., disconencted */
USB_TRANSFER_STATUS_OVERFLOW, /**< The transfer as more data was sent than was requested */
} usb_transfer_status_t;
/**
* @brief Isochronous packet descriptor
*
* If the number of bytes in an IRP transfer is larger than the MPS of the
* endpoint, the IRP is split over multiple packets (one packet per bInterval
* of the endpoint). An array of Isochronous packet descriptos describes how
* an IRP should be split over multiple packets.
*/
typedef struct {
int length; /**< Number of bytes to transmit/receive in the packet */
int actual_length; /**< Actual number of bytes transmitted/received in the packet */
usb_transfer_status_t status; /**< Status of the packet */
} usb_iso_packet_desc_t;
/**
* @brief USB IRP (I/O Request Packet). See USB2.0 Spec
*
* An identifiable request by a software client to move data between itself (on the
* host) and an endpoint of a device in an appropriate direction.
*
* This structure represents the barebones of the request. Different layers of
* USB drivers will wrap their own objects around this.
*
* See 10.5.3.1 os USB2.0 specification
* Bulk: Represnts a single bulk transfer which a pipe will transparently split
* into multiple MPS transactions (until the last)
* Control: Represents a single contorl transfer with the setup packet at the
* first 8 bytes of the buffer.
* Interrupt: Represnts a single interrupt transaction
* Isochronous: Represnts a buffer of a stream of bytes which the pipe will transparently
* transfer the stream of bytes one or more service periods
*/
typedef struct {
int num_bytes; /**< Number of bytes in IRP. Control should exclude size of setup. IN should be integer multiple of MPS */
int actual_num_bytes; /**< Actual number of bytes transmitted/receives in the IRP */
uint8_t *data_buffer; /**< Pointer to data buffer. Must be DMA capable memory */
usb_transfer_status_t status; /**< Status of the transfer */
int num_iso_packets; /**< Only relevant to isochronous. Number of service periods to transfer data buffer over. Set to 0 for non-iso transfers */
usb_iso_packet_desc_t iso_packet_desc[0]; /**< Descriptors for each ISO packet */
} usb_irp_t;
/* -----------------------------------------------------------------------------
----------------------------------- Chapter 9 ----------------------------------
----------------------------------------------------------------------------- */
// ------------------------------ Control Request ------------------------------
/**
* @brief Size of a USB control transfer setup packet in bytes
*/
#define USB_CTRL_REQ_SIZE 8
/**
* @brief Structure representing a USB control transfer setup packet
*/
typedef union {
struct {
uint8_t bRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} USB_CTRL_REQ_ATTR;
uint8_t val[USB_CTRL_REQ_SIZE];
} usb_ctrl_req_t;
_Static_assert(sizeof(usb_ctrl_req_t) == USB_CTRL_REQ_SIZE, "Size of usb_ctrl_req_t incorrect");
/**
* @brief Bit masks pertaining to the bRequestType field of a setup packet
*/
#define USB_B_REQUEST_TYPE_DIR_OUT (0X00 << 7)
#define USB_B_REQUEST_TYPE_DIR_IN (0x01 << 7)
#define USB_B_REQUEST_TYPE_TYPE_STANDARD (0x00 << 5)
#define USB_B_REQUEST_TYPE_TYPE_CLASS (0x01 << 5)
#define USB_B_REQUEST_TYPE_TYPE_VENDOR (0x02 << 5)
#define USB_B_REQUEST_TYPE_TYPE_RESERVED (0x03 << 5)
#define USB_B_REQUEST_TYPE_TYPE_MASK (0x03 << 5)
#define USB_B_REQUEST_TYPE_RECIP_DEVICE (0x00 << 0)
#define USB_B_REQUEST_TYPE_RECIP_INTERFACE (0x01 << 0)
#define USB_B_REQUEST_TYPE_RECIP_ENDPOINT (0x02 << 0)
#define USB_B_REQUEST_TYPE_RECIP_OTHER (0x03 << 0)
#define USB_B_REQUEST_TYPE_RECIP_MASK (0x1f << 0)
/**
* @brief Bit masks pertaining to the bRequest field of a setup packet
*/
#define USB_B_REQUEST_GET_STATUS 0x00
#define USB_B_REQUEST_CLEAR_FEATURE 0x01
#define USB_B_REQUEST_SET_FEATURE 0x03
#define USB_B_REQUEST_SET_ADDRESS 0x05
#define USB_B_REQUEST_GET_DESCRIPTOR 0x06
#define USB_B_REQUEST_SET_DESCRIPTOR 0x07
#define USB_B_REQUEST_GET_CONFIGURATION 0x08
#define USB_B_REQUEST_SET_CONFIGURATION 0x09
#define USB_B_REQUEST_GET_INTERFACE 0x0A
#define USB_B_REQUEST_SET_INTERFACE 0x0B
#define USB_B_REQUEST_SYNCH_FRAME 0x0C
/**
* @brief Bit masks pertaining to the wValue field of a setup packet
*/
#define USB_W_VALUE_DT_DEVICE 0x01
#define USB_W_VALUE_DT_CONFIG 0x02
#define USB_W_VALUE_DT_STRING 0x03
#define USB_W_VALUE_DT_INTERFACE 0x04
#define USB_W_VALUE_DT_ENDPOINT 0x05
#define USB_W_VALUE_DT_DEVICE_QUALIFIER 0x06
#define USB_W_VALUE_DT_OTHER_SPEED_CONFIG 0x07
#define USB_W_VALUE_DT_INTERFACE_POWER 0x08
/**
* @brief Initializer for a SET_ADDRESS request
*
* Sets the address of a connected device
*/
#define USB_CTRL_REQ_INIT_SET_ADDR(ctrl_req_ptr, addr) ({ \
(ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_OUT | USB_B_REQUEST_TYPE_TYPE_STANDARD |USB_B_REQUEST_TYPE_RECIP_DEVICE; \
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_SET_ADDRESS; \
(ctrl_req_ptr)->wValue = (addr); \
(ctrl_req_ptr)->wIndex = 0; \
(ctrl_req_ptr)->wLength = 0; \
})
/**
* @brief Initializer for a request to get a device's device descriptor
*/
#define USB_CTRL_REQ_INIT_GET_DEVC_DESC(ctrl_req_ptr) ({ \
(ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_IN | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \
(ctrl_req_ptr)->wValue = (USB_W_VALUE_DT_DEVICE << 8); \
(ctrl_req_ptr)->wIndex = 0; \
(ctrl_req_ptr)->wLength = 18; \
})
/**
* @brief Initializer for a request to get a device's current configuration number
*/
#define USB_CTRL_REQ_INIT_GET_CONFIG(ctrl_req_ptr) ({ \
(ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_IN | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_GET_CONFIGURATION; \
(ctrl_req_ptr)->wValue = 0; \
(ctrl_req_ptr)->wIndex = 0; \
(ctrl_req_ptr)->wLength = 1; \
})
/**
* @brief Initializer for a request to get one of the device's current configuration descriptor
*
* - desc_index indicates the configuration's index number
* - Number of bytes of the configuration descriptor to get
*/
#define USB_CTRL_REQ_INIT_GET_CFG_DESC(ctrl_req_ptr, desc_index, desc_len) ({ \
(ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_IN | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \
(ctrl_req_ptr)->wValue = (USB_W_VALUE_DT_CONFIG << 8) | ((desc_index) & 0xFF); \
(ctrl_req_ptr)->wIndex = 0; \
(ctrl_req_ptr)->wLength = (desc_len); \
})
/**
* @brief Initializer for a request to set a device's current configuration number
*/
#define USB_CTRL_REQ_INIT_SET_CONFIG(ctrl_req_ptr, config_num) ({ \
(ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_OUT | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \
(ctrl_req_ptr)->bRequest = USB_B_REQUEST_SET_CONFIGURATION; \
(ctrl_req_ptr)->wValue = (config_num); \
(ctrl_req_ptr)->wIndex = 0; \
(ctrl_req_ptr)->wLength = 0; \
})
// ---------------------------- Device Descriptor ------------------------------
/**
* @brief Size of a USB device descriptor in bytes
*/
#define USB_DESC_DEV_SIZE 18
/**
* @brief Structure representing a USB device descriptor
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} USB_DESC_ATTR;
uint8_t val[USB_DESC_DEV_SIZE];
} usb_desc_devc_t;
_Static_assert(sizeof(usb_desc_devc_t) == USB_DESC_DEV_SIZE, "Size of usb_desc_devc_t incorrect");
/**
* @brief Possible base class values of the bDeviceClass field of a USB device descriptor
*/
#define USB_CLASS_PER_INTERFACE 0x00
#define USB_CLASS_AUDIO 0x01
#define USB_CLASS_COMM 0x02
#define USB_CLASS_HID 0x03
#define USB_CLASS_PHYSICAL 0x05
#define USB_CLASS_STILL_IMAGE 0x06
#define USB_CLASS_PRINTER 0x07
#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b
#define USB_CLASS_CONTENT_SEC 0x0d
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_PERSONAL_HEALTHCARE 0x0f
#define USB_CLASS_AUDIO_VIDEO 0x10
#define USB_CLASS_BILLBOARD 0x11
#define USB_CLASS_USB_TYPE_C_BRIDGE 0x12
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
/**
* @brief Vendor specific subclass code
*/
#define USB_SUBCLASS_VENDOR_SPEC 0xff
// ----------------------- Configuration Descriptor ----------------------------
/**
* @brief Size of a short USB configuration descriptor in bytes
*
* @note The size of a full USB configuration includes all the interface and endpoint
* descriptors of that configuration.
*/
#define USB_DESC_CFG_SIZE 9
/**
* @brief Structure representing a short USB configuration descriptor
*
* @note The full USB configuration includes all the interface and endpoint
* descriptors of that configuration.
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} USB_DESC_ATTR;
uint8_t val[USB_DESC_CFG_SIZE];
} usb_desc_cfg_t;
_Static_assert(sizeof(usb_desc_cfg_t) == USB_DESC_CFG_SIZE, "Size of usb_desc_cfg_t incorrect");
/**
* @brief Bit masks pertaining to the bmAttributes field of a configuration descriptor
*/
#define USB_BM_ATTRIBUTES_ONE (1 << 7) //Must be set
#define USB_BM_ATTRIBUTES_SELFPOWER (1 << 6) //Self powered
#define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) //Can wakeup
#define USB_BM_ATTRIBUTES_BATTERY (1 << 4) //Battery powered
// ------------------------- Interface Descriptor ------------------------------
/**
* @brief Size of a USB interface descriptor in bytes
*/
#define USB_DESC_INTF_SIZE 9
/**
* @brief Structure representing a USB interface descriptor
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} USB_DESC_ATTR;
uint8_t val[USB_DESC_INTF_SIZE];
} usb_desc_intf_t;
_Static_assert(sizeof(usb_desc_intf_t) == USB_DESC_INTF_SIZE, "Size of usb_desc_intf_t incorrect");
// ------------------------- Endpoint Descriptor -------------------------------
/**
* @brief Size of a USB endpoint descriptor in bytes
*/
#define USB_DESC_EP_SIZE 7
/**
* @brief Structure representing a USB endp;oint descriptor
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} USB_DESC_ATTR;
uint8_t val[USB_DESC_EP_SIZE];
} usb_desc_ep_t;
_Static_assert(sizeof(usb_desc_ep_t) == USB_DESC_EP_SIZE, "Size of usb_desc_ep_t incorrect");
/**
* @brief Bit masks pertaining to the bEndpointAddress field of an endpoint descriptor
*/
#define USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK 0x0f
#define USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK 0x80
/**
* @brief Bit masks pertaining to the bmAttributes field of an endpoint descriptor
*/
#define USB_BM_ATTRIBUTES_XFERTYPE_MASK 0x03
#define USB_BM_ATTRIBUTES_XFER_CONTROL (0 << 0)
#define USB_BM_ATTRIBUTES_XFER_ISOC (1 << 0)
#define USB_BM_ATTRIBUTES_XFER_BULK (2 << 0)
#define USB_BM_ATTRIBUTES_XFER_INT (3 << 0)
#define USB_BM_ATTRIBUTES_SYNCTYPE_MASK 0x0C /* in bmAttributes */
#define USB_BM_ATTRIBUTES_SYNC_NONE (0 << 2)
#define USB_BM_ATTRIBUTES_SYNC_ASYNC (1 << 2)
#define USB_BM_ATTRIBUTES_SYNC_ADAPTIVE (2 << 2)
#define USB_BM_ATTRIBUTES_SYNC_SYNC (3 << 2)
#define USB_BM_ATTRIBUTES_USAGETYPE_MASK 0x30
#define USB_BM_ATTRIBUTES_USAGE_DATA (0 << 4)
#define USB_BM_ATTRIBUTES_USAGE_FEEDBACK (1 << 4)
#define USB_BM_ATTRIBUTES_USAGE_IMPLICIT_FB (2 << 4)
/**
* @brief Macro helpers to get information about an endpoint from its descriptor
*/
#define USB_DESC_EP_GET_XFERTYPE(desc_ptr) ((usb_xfer_type_t) ((desc_ptr)->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK))
#define USB_DESC_EP_GET_EP_NUM(desc_ptr) ((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK)
#define USB_DESC_EP_GET_EP_DIR(desc_ptr) (((desc_ptr)->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) ? 1 : 0)
#define USB_DESC_EP_GET_MPS(desc_ptr) ((desc_ptr)->wMaxPacketSize & 0x7FF)
// --------------------------- String Descriptor -------------------------------
/**
* @brief Size of a short USB string descriptor in bytes
*/
#define USB_DESC_STR_SIZE 4
/**
* @brief Structure representing a USB string descriptor
*/
typedef union {
struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[1]; /* UTF-16LE encoded */
} USB_DESC_ATTR;
uint8_t val[USB_DESC_STR_SIZE];
} usb_desc_str_t;
_Static_assert(sizeof(usb_desc_str_t) == USB_DESC_STR_SIZE, "Size of usb_desc_str_t incorrect");
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,180 @@
// 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 <stdbool.h>
#include "soc/soc_caps.h"
#include "hal/wdt_types.h"
#include "hal/mwdt_ll.h"
#include "hal/rwdt_ll.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
wdt_inst_t inst; /**< Which WDT instance this HAL context is using (i.e. MWDT0, MWDT1, RWDT)*/
union {
timg_dev_t *mwdt_dev; /**< Starting address of the MWDT */
rtc_cntl_dev_t *rwdt_dev; /**< Starting address of the RWDT*/
};
} wdt_hal_context_t;
/* ---------------------------- Init and Config ----------------------------- */
/**
* @brief Initialize one of the WDTs associated HAL context
*
* This function initializes one of the WDTs (MWDT0, MWDT1, or RWDT) hardware by
* doing the following:
* - Disables the WDT and all of its stages
* - Sets some registers with default values
* - Sets the WDTs source clock prescaler (not applicable to RWDT)
* - Optionally enables the level interrupt
*
* The HAL context is initialized by storing the type (i.e. MWDT or RWDT) of
* this WDT instance, and a pointer to the associated registers.
*
* @param hal Context of HAL layer
* @param wdt_inst Which WDT instance to initialize (MWDT0, MWDT1, or RWDT)
* @param prescaler MWDT source clock prescaler. Unused for RWDT
* @param enable_intr True to enable level interrupt. False to disable
*
* @note Although the WDTs on the ESP32 have an edge interrupt, this HAL does
* not utilize it and will always disables it.
* @note RWDT does not have a prescaler. Its tick rate is equal to the
* frequency of its source clock (RTC slow clock).
*/
void wdt_hal_init(wdt_hal_context_t *hal, wdt_inst_t wdt_inst, uint32_t prescaler, bool enable_intr);
/**
* @brief Deinitialize a WDT and its HAL context
*
* This function deinitializes a WDT by feeding then disabling it. The WDT's
* interrupt is also cleared and disabled. The HAL context is cleared.
*
* @param hal Context of HAL layer
*/
void wdt_hal_deinit(wdt_hal_context_t *hal);
/**
* @brief Configure a particular stage of a WDT
*
* @param hal Context of HAL layer
* @param stage Stage to configure (0 to 3)
* @param timeout Number of WDT ticks for the stage to time out
* @param behavior What action to take when the stage times out. Note that only
* the RWDT supports the RTC reset action.
*
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior);
/* -------------------------------- Runtime --------------------------------- */
/**
* @brief Disable write protection of the WDT registers
*
* @param hal Context of HAL layer
*/
void wdt_hal_write_protect_disable(wdt_hal_context_t *hal);
/**
* @brief Enable write protection of the WDT registers
*
* @param hal Context of HAL layer
*/
void wdt_hal_write_protect_enable(wdt_hal_context_t *hal);
/**
* @brief Enable the WDT
*
* The WDT will start counting when enabled. This function also feeds the WDT
* before enabling it.
*
* @param hal Context of HAL layer
*
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_enable(wdt_hal_context_t *hal);
/**
* @brief Disable the WDT
*
* @param hal Context of HAL layer
*
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_disable(wdt_hal_context_t *hal);
/**
* @brief Handle WDT interrupt
*
* Clears the interrupt status bit and feeds the WDT
*
* @param hal Context of HAL layer
*
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_handle_intr(wdt_hal_context_t *hal);
/**
* @brief Feed the WDT
*
* Feeding the WDT will reset the internal count and current stage.
*
* @param hal Context of HAL layer
*
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_feed(wdt_hal_context_t *hal);
/**
* @brief Enable/Disable the WDT flash boot mode
*
* @param hal Context of HAL layer
* @param enable True to enable flash boot mode, false to disable.
*
* @note Flash boot mode can trigger a time out even if the WDT is disabled.
* @note This function can only be called when the WDT is unlocked. Call
* wdt_hal_write_protect_disable() first.
*/
void wdt_hal_set_flashboot_en(wdt_hal_context_t *hal, bool enable);
/**
* @brief Check if the WDT is enabled
*
* @param hal Context of HAL layer
* @return True if enabled, false otherwise
*/
bool wdt_hal_is_enabled(wdt_hal_context_t *hal);
#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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
WDT_RWDT = 0, /*!< RTC Watchdog Timer (RWDT) */
WDT_MWDT0, /*!< Main System Watchdog Timer (MWDT) of Timer Group 0 */
WDT_MWDT1, /*!< Main System Watchdog Timer (MWDT) of Timer Group 1 */
} wdt_inst_t;
/**
* @brief Stages of a Watchdog Timer. A WDT has 4 stages.
*/
typedef enum {
WDT_STAGE0 = 0, /*!< Stage 0 */
WDT_STAGE1 = 1, /*!< Stage 1 */
WDT_STAGE2 = 2, /*!< Stage 2 */
WDT_STAGE3 = 3 /*!< Stage 3 */
} wdt_stage_t;
/**
* @brief Behavior of the WDT stage if it times out
*
* @note These enum values should be compatible with the corresponding register
* field values.
*/
typedef enum {
WDT_STAGE_ACTION_OFF = 0, /*!< Disabled. This stage will have no effects on the system. */
WDT_STAGE_ACTION_INT = 1, /*!< Trigger an interrupt when the stage expires. */
WDT_STAGE_ACTION_RESET_CPU = 2, /*!< Reset a CPU core when the stage expires. */
WDT_STAGE_ACTION_RESET_SYSTEM = 3, /*!< Reset the main system when the stage expires. This includes the CPU and all peripherals. The RTC is an exception and will not be reset. */
WDT_STAGE_ACTION_RESET_RTC = 4, /*!< Reset the main system and the RTC when the stage expires. ONLY AVAILABLE FOR RWDT */
} wdt_stage_action_t;
/**
* @brief Length of CPU or System Reset signals
*
* @note These enum values should be compatible with the corresponding register
* field values.
*/
typedef enum {
WDT_RESET_SIG_LENGTH_100ns = 0, /*!< 100 ns */
WDT_RESET_SIG_LENGTH_200ns = 1, /*!< 200 ns */
WDT_RESET_SIG_LENGTH_300ns = 2, /*!< 300 ns */
WDT_RESET_SIG_LENGTH_400ns = 3, /*!< 400 ns */
WDT_RESET_SIG_LENGTH_500ns = 4, /*!< 500 ns */
WDT_RESET_SIG_LENGTH_800ns = 5, /*!< 800 ns */
WDT_RESET_SIG_LENGTH_1_6us = 6, /*!< 1.6 us */
WDT_RESET_SIG_LENGTH_3_2us = 7 /*!< 3.2 us */
} wdt_reset_sig_length_t;
#ifdef __cplusplus
}
#endif