mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
hal: extract hal component from soc component
This commit is contained in:
72
components/hal/esp32/include/hal/adc_hal.h
Normal file
72
components/hal/esp32/include/hal/adc_hal.h
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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 soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The HAL layer for ADC (esp32 specific part)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/adc_ll.h"
|
||||
#include "hal/adc_types.h"
|
||||
|
||||
#include_next "hal/adc_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Digital controller setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Set I2S DMA data source for digital controller.
|
||||
*
|
||||
* @param src i2s data source.
|
||||
*/
|
||||
#define adc_hal_digi_set_data_source(src) adc_ll_digi_set_data_source(src)
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Common setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Hall sensor setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Enable hall sensor.
|
||||
*/
|
||||
#define adc_hal_hall_enable() adc_ll_hall_enable()
|
||||
|
||||
/**
|
||||
* Disable hall sensor.
|
||||
*/
|
||||
#define adc_hal_hall_disable() adc_ll_hall_disable()
|
||||
|
||||
/**
|
||||
* Start hall convert and return the hall value.
|
||||
*
|
||||
* @return Hall value.
|
||||
*/
|
||||
int adc_hal_hall_convert(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
690
components/hal/esp32/include/hal/adc_ll.h
Normal file
690
components/hal/esp32/include/hal/adc_ll.h
Normal file
@@ -0,0 +1,690 @@
|
||||
#pragma once
|
||||
|
||||
#include "soc/adc_periph.h"
|
||||
#include "hal/adc_types.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ADC_NUM_1 = 0, /*!< SAR ADC 1 */
|
||||
ADC_NUM_2 = 1, /*!< SAR ADC 2 */
|
||||
ADC_NUM_MAX,
|
||||
} adc_ll_num_t;
|
||||
|
||||
typedef enum {
|
||||
ADC_POWER_BY_FSM, /*!< ADC XPD controlled by FSM. Used for polling mode */
|
||||
ADC_POWER_SW_ON, /*!< ADC XPD controlled by SW. power on. Used for DMA mode */
|
||||
ADC_POWER_SW_OFF, /*!< ADC XPD controlled by SW. power off. */
|
||||
ADC_POWER_MAX, /*!< For parameter check. */
|
||||
} adc_ll_power_t;
|
||||
|
||||
typedef enum {
|
||||
ADC_HALL_CTRL_ULP = 0x0,/*!< Hall sensor controlled by ULP */
|
||||
ADC_HALL_CTRL_RTC = 0x1 /*!< Hall sensor controlled by RTC */
|
||||
} adc_ll_hall_controller_t ;
|
||||
|
||||
typedef enum {
|
||||
ADC_CTRL_RTC = 0,
|
||||
ADC_CTRL_ULP = 1,
|
||||
ADC_CTRL_DIG = 2,
|
||||
ADC2_CTRL_PWDET = 3,
|
||||
} adc_hal_controller_t ;
|
||||
|
||||
typedef enum {
|
||||
ADC_RTC_DATA_OK = 0,
|
||||
} adc_ll_rtc_raw_data_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
|
||||
SYSCON.saradc_fsm.rstb_wait = rst_wait;
|
||||
// Internal FSM start wait time
|
||||
SYSCON.saradc_fsm.start_wait = start_wait;
|
||||
// Internal FSM standby wait time
|
||||
SYSCON.saradc_fsm.standby_wait = standby_wait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set adc sample cycle.
|
||||
*
|
||||
* @note Normally, please use default value.
|
||||
* @param sample_cycle The number of ADC sampling cycles. Range: 1 ~ 7.
|
||||
*/
|
||||
static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle)
|
||||
{
|
||||
SYSCON.saradc_fsm.sample_cycle = sample_cycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADC module clock division factor setting. ADC clock divided from APB clock.
|
||||
*
|
||||
* @param div Division factor.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_clk_div(uint32_t div)
|
||||
{
|
||||
/* ADC clock divided from APB clk, e.g. 80 / 2 = 40Mhz, */
|
||||
SYSCON.saradc_ctrl.sar_clk_div = div;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set adc output data format for digital controller.
|
||||
*
|
||||
* @param format Output data format, see ``adc_digi_output_format_t``.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_output_format(adc_digi_output_format_t format)
|
||||
{
|
||||
SYSCON.saradc_ctrl.data_sar_sel = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
SYSCON.saradc_ctrl2.max_meas_num = meas_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable max conversion number detection for digital controller.
|
||||
* If the number of ADC conversion is equal to the maximum, the conversion is stopped.
|
||||
*/
|
||||
static inline void adc_ll_digi_convert_limit_enable(void)
|
||||
{
|
||||
SYSCON.saradc_ctrl2.meas_num_limit = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable max conversion number detection for digital controller.
|
||||
* If the number of ADC conversion is equal to the maximum, the conversion is stopped.
|
||||
*/
|
||||
static inline void adc_ll_digi_convert_limit_disable(void)
|
||||
{
|
||||
SYSCON.saradc_ctrl2.meas_num_limit = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set adc conversion mode for digital controller.
|
||||
*
|
||||
* @note ESP32 only support ADC1 single mode.
|
||||
*
|
||||
* @param mode Conversion mode select, see ``adc_digi_convert_mode_t``.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_convert_mode(adc_digi_convert_mode_t mode)
|
||||
{
|
||||
if (mode == ADC_CONV_SINGLE_UNIT_1) {
|
||||
SYSCON.saradc_ctrl.work_mode = 0;
|
||||
SYSCON.saradc_ctrl.sar_sel = 0;
|
||||
} else if (mode == ADC_CONV_SINGLE_UNIT_2) {
|
||||
SYSCON.saradc_ctrl.work_mode = 0;
|
||||
SYSCON.saradc_ctrl.sar_sel = 1;
|
||||
} else if (mode == ADC_CONV_BOTH_UNIT) {
|
||||
SYSCON.saradc_ctrl.work_mode = 1;
|
||||
} else if (mode == ADC_CONV_ALTER_UNIT) {
|
||||
SYSCON.saradc_ctrl.work_mode = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ADC module Digital output data invert or not.
|
||||
*
|
||||
* @prarm adc_n ADC unit.
|
||||
*/
|
||||
static inline void adc_ll_digi_output_invert(adc_ll_num_t adc_n, bool inv_en)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SYSCON.saradc_ctrl2.sar1_inv = inv_en; // Enable / Disable ADC data invert
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SYSCON.saradc_ctrl2.sar2_inv = inv_en; // Enable / Disable ADC data invert
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set I2S DMA data source for digital controller.
|
||||
*
|
||||
* @param src i2s data source, see ``adc_i2s_source_t``.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_data_source(adc_i2s_source_t src)
|
||||
{
|
||||
/* 1: I2S input data is from SAR ADC (for DMA) 0: I2S input data is from GPIO matrix */
|
||||
SYSCON.saradc_ctrl.data_to_i2s = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pattern table length for digital controller.
|
||||
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
|
||||
* resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
* pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param patt_len Items range: 1 ~ 16.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_pattern_table_len(adc_ll_num_t adc_n, uint32_t patt_len)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SYSCON.saradc_ctrl.sar1_patt_len = patt_len - 1;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SYSCON.saradc_ctrl.sar2_patt_len = patt_len - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pattern table lenth for digital controller.
|
||||
* The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
|
||||
* resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
|
||||
* pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param pattern_index Items index. Range: 0 ~ 15.
|
||||
* @param pattern Stored conversion rules, see ``adc_digi_pattern_table_t``.
|
||||
*/
|
||||
static inline void adc_ll_digi_set_pattern_table(adc_ll_num_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
|
||||
{
|
||||
uint32_t tab;
|
||||
uint8_t index = pattern_index / 4;
|
||||
uint8_t offset = (pattern_index % 4) * 8;
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value
|
||||
tab &= (~(0xFF000000 >> offset)); // clear old data
|
||||
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
|
||||
SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the pattern table pointer, then take the measurement rule from table header in next measurement.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
*/
|
||||
static inline void adc_ll_digi_clear_pattern_table(adc_ll_num_t adc_n)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SYSCON.saradc_ctrl.sar1_patt_p_clear = 1;
|
||||
SYSCON.saradc_ctrl.sar1_patt_p_clear = 0;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SYSCON.saradc_ctrl.sar2_patt_p_clear = 1;
|
||||
SYSCON.saradc_ctrl.sar2_patt_p_clear = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
PWDET(Power detect) controller setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Set adc cct for PWDET controller.
|
||||
*
|
||||
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
|
||||
* @param cct Range: 0 ~ 7.
|
||||
*/
|
||||
static inline void adc_ll_pwdet_set_cct(uint32_t cct)
|
||||
{
|
||||
/* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */
|
||||
SENS.sar_start_force.sar2_pwdet_cct = cct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get adc cct for PWDET controller.
|
||||
*
|
||||
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
|
||||
* @return cct Range: 0 ~ 7.
|
||||
*/
|
||||
static inline uint32_t adc_ll_pwdet_get_cct(void)
|
||||
{
|
||||
/* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */
|
||||
return SENS.sar_start_force.sar2_pwdet_cct;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
RTC controller setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Set adc output data format for RTC controller.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param bits Output data bits width option, see ``adc_bits_width_t``.
|
||||
*/
|
||||
static inline void adc_ll_rtc_set_output_format(adc_ll_num_t adc_n, adc_bits_width_t bits)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_start_force.sar1_bit_width = bits;
|
||||
SENS.sar_read_ctrl.sar1_sample_bit = bits;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_start_force.sar2_bit_width = bits;
|
||||
SENS.sar_read_ctrl2.sar2_sample_bit = bits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable adc channel to start convert.
|
||||
*
|
||||
* @note Only one channel can be selected in once measurement.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param channel ADC channel number for each ADCn.
|
||||
*/
|
||||
static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_meas_start1.sar1_en_pad = (1 << channel); //only one channel is selected.
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_meas_start2.sar2_en_pad = (1 << channel); //only one channel is selected.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable adc channel to start convert.
|
||||
*
|
||||
* @note Only one channel can be selected in once measurement.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param channel ADC channel number for each ADCn.
|
||||
*/
|
||||
static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_meas_start1.sar1_en_pad = 0; //only one channel is selected.
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_meas_start2.sar2_en_pad = 0; //only one channel is selected.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start conversion once by software for RTC controller.
|
||||
*
|
||||
* @note It may be block to wait conversion idle for ADC1.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param channel ADC channel number for each ADCn.
|
||||
*/
|
||||
static inline void adc_ll_rtc_start_convert(adc_ll_num_t adc_n, int channel)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
while (SENS.sar_slave_addr1.meas_status != 0);
|
||||
SENS.sar_meas_start1.meas1_start_sar = 0;
|
||||
SENS.sar_meas_start1.meas1_start_sar = 1;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_meas_start2.meas2_start_sar = 0; //start force 0
|
||||
SENS.sar_meas_start2.meas2_start_sar = 1; //start force 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the conversion done flag for each ADCn for RTC controller.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @return
|
||||
* -true : The conversion process is finish.
|
||||
* -false : The conversion process is not finish.
|
||||
*/
|
||||
static inline bool adc_ll_rtc_convert_is_done(adc_ll_num_t adc_n)
|
||||
{
|
||||
bool ret = true;
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
ret = (bool)SENS.sar_meas_start1.meas1_done_sar;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
ret = (bool)SENS.sar_meas_start2.meas2_done_sar;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the converted value for each ADCn for RTC controller.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @return
|
||||
* - Converted value.
|
||||
*/
|
||||
static inline int adc_ll_rtc_get_convert_value(adc_ll_num_t adc_n)
|
||||
{
|
||||
int ret_val = 0;
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
ret_val = SENS.sar_meas_start1.meas1_data_sar;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
ret_val = SENS.sar_meas_start2.meas2_data_sar;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADC module RTC output data invert or not.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
*/
|
||||
static inline void adc_ll_rtc_output_invert(adc_ll_num_t adc_n, bool inv_en)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_read_ctrl.sar1_data_inv = inv_en; // Enable / Disable ADC data invert
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_read_ctrl2.sar2_data_inv = inv_en; // Enable / Disable ADC data invert
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze whether the obtained raw data is correct.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param raw_data ADC raw data input (convert value).
|
||||
* @return
|
||||
* - 0: The data is correct to use.
|
||||
*/
|
||||
static inline adc_ll_rtc_raw_data_t adc_ll_rtc_analysis_raw_data(adc_ll_num_t adc_n, uint16_t raw_data)
|
||||
{
|
||||
/* ADC1 don't need check data */
|
||||
return ADC_RTC_DATA_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Common setting
|
||||
---------------------------------------------------------------*/
|
||||
/**
|
||||
* Set ADC module power management.
|
||||
*
|
||||
* @param manage Set ADC power status.
|
||||
*/
|
||||
static inline void adc_ll_set_power_manage(adc_ll_power_t manage)
|
||||
{
|
||||
/* Bit1 0:Fsm 1: SW mode
|
||||
Bit0 0:SW mode power down 1: SW mode power on */
|
||||
if (manage == ADC_POWER_SW_ON) {
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
|
||||
} else if (manage == ADC_POWER_BY_FSM) {
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_FSM;
|
||||
} else if (manage == ADC_POWER_SW_OFF) {
|
||||
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (SENS.sar_meas_wait2.force_xpd_sar == SENS_FORCE_XPD_SAR_PU) {
|
||||
manage = ADC_POWER_SW_ON;
|
||||
} else if (SENS.sar_meas_wait2.force_xpd_sar == SENS_FORCE_XPD_SAR_PD) {
|
||||
manage = ADC_POWER_SW_OFF;
|
||||
} else {
|
||||
manage = ADC_POWER_BY_FSM;
|
||||
}
|
||||
return manage;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADC SAR clock division factor setting. ADC SAR clock divided from `RTC_FAST_CLK`.
|
||||
*
|
||||
* @param div Division factor.
|
||||
*/
|
||||
static inline void adc_ll_set_sar_clk_div(adc_ll_num_t adc_n, uint32_t div)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_read_ctrl.sar1_clk_div = div;
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_read_ctrl2.sar2_clk_div = div;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 attenuation (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 attenuation (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 The attenuation option.
|
||||
*/
|
||||
static inline void adc_ll_set_atten(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
SENS.sar_atten1 = ( SENS.sar_atten1 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2));
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
SENS.sar_atten2 = ( SENS.sar_atten2 & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attenuation of a particular channel on ADCn.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param channel ADCn channel number.
|
||||
* @return atten The attenuation option.
|
||||
*/
|
||||
static inline adc_atten_t adc_ll_get_atten(adc_ll_num_t adc_n, adc_channel_t channel)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
return (adc_atten_t)((SENS.sar_atten1 >> (channel * 2)) & 0x3);
|
||||
} else {
|
||||
return (adc_atten_t)((SENS.sar_atten2 >> (channel * 2)) & 0x3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ADC module controller.
|
||||
* There are five SAR ADC controllers:
|
||||
* Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes;
|
||||
* Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep;
|
||||
* the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2.
|
||||
*
|
||||
* @param adc_n ADC unit.
|
||||
* @param ctrl ADC controller.
|
||||
*/
|
||||
static inline void adc_ll_set_controller(adc_ll_num_t adc_n, adc_hal_controller_t ctrl)
|
||||
{
|
||||
if (adc_n == ADC_NUM_1) {
|
||||
switch ( ctrl ) {
|
||||
case ADC_CTRL_RTC:
|
||||
SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power.
|
||||
SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
|
||||
break;
|
||||
case ADC_CTRL_ULP:
|
||||
SENS.sar_read_ctrl.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_meas_start1.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start1.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_touch_ctrl1.xpd_hall_force = 0; // 1: SW control HALL power; 0: ULP FSM control HALL power.
|
||||
SENS.sar_touch_ctrl1.hall_phase_force = 0; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
|
||||
break;
|
||||
case ADC_CTRL_DIG:
|
||||
SENS.sar_read_ctrl.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_meas_start1.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start1.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_touch_ctrl1.xpd_hall_force = 1; // 1: SW control HALL power; 0: ULP FSM control HALL power.
|
||||
SENS.sar_touch_ctrl1.hall_phase_force = 1; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else { // adc_n == ADC_NUM_2
|
||||
switch ( ctrl ) {
|
||||
case ADC_CTRL_RTC:
|
||||
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
|
||||
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
|
||||
break;
|
||||
case ADC_CTRL_ULP:
|
||||
SENS.sar_meas_start2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
|
||||
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
|
||||
break;
|
||||
case ADC_CTRL_DIG:
|
||||
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_read_ctrl2.sar2_dig_force = 1; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_read_ctrl2.sar2_pwdet_force = 0; // 1: Select power detect control; 0: Select RTC control.
|
||||
SYSCON.saradc_ctrl.sar2_mux = 1; // 1: Select digital control; 0: Select power detect control.
|
||||
break;
|
||||
case ADC2_CTRL_PWDET: // currently only used by Wi-Fi
|
||||
SENS.sar_meas_start2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start.
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map;
|
||||
SENS.sar_read_ctrl2.sar2_dig_force = 0; // 1: Select digital control; 0: Select RTC control.
|
||||
SENS.sar_read_ctrl2.sar2_pwdet_force = 1; // 1: Select power detect control; 0: Select RTC control.
|
||||
SYSCON.saradc_ctrl.sar2_mux = 0; // 1: Select digital control; 0: Select power detect control.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close ADC AMP module if don't use it for power save.
|
||||
*/
|
||||
static inline void adc_ll_amp_disable(void)
|
||||
{
|
||||
//channel is set in the convert function
|
||||
SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD;
|
||||
//disable FSM, it's only used by the LNA.
|
||||
SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
|
||||
SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
|
||||
SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
|
||||
SENS.sar_meas_wait1.sar_amp_wait1 = 1;
|
||||
SENS.sar_meas_wait1.sar_amp_wait2 = 1;
|
||||
SENS.sar_meas_wait2.sar_amp_wait3 = 1;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------
|
||||
Hall sensor setting
|
||||
---------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Enable hall sensor.
|
||||
*/
|
||||
static inline void adc_ll_hall_enable(void)
|
||||
{
|
||||
RTCIO.hall_sens.xpd_hall = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable hall sensor.
|
||||
*/
|
||||
static inline void adc_ll_hall_disable(void)
|
||||
{
|
||||
RTCIO.hall_sens.xpd_hall = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse phase of hall sensor.
|
||||
*/
|
||||
static inline void adc_ll_hall_phase_enable(void)
|
||||
{
|
||||
RTCIO.hall_sens.hall_phase = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't reverse phase of hall sensor.
|
||||
*/
|
||||
static inline void adc_ll_hall_phase_disable(void)
|
||||
{
|
||||
RTCIO.hall_sens.hall_phase = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hall sensor controller.
|
||||
*
|
||||
* @param hall_ctrl Hall controller.
|
||||
*/
|
||||
static inline void adc_ll_set_hall_controller(adc_ll_hall_controller_t hall_ctrl)
|
||||
{
|
||||
SENS.sar_touch_ctrl1.xpd_hall_force = hall_ctrl; // 1: SW control HALL power; 0: ULP FSM control HALL power.
|
||||
SENS.sar_touch_ctrl1.hall_phase_force = hall_ctrl; // 1: SW control HALL phase; 0: ULP FSM control HALL phase.
|
||||
}
|
||||
|
||||
/**
|
||||
* Output ADC internal reference voltage to channels, only available for ADC2 on ESP32.
|
||||
*
|
||||
* This function routes the internal reference voltage of ADCn to one of
|
||||
* ADC2's channels. This reference voltage can then be manually measured
|
||||
* for calibration purposes.
|
||||
*
|
||||
* @param[in] adc ADC unit select
|
||||
* @param[in] channel ADC2 channel number
|
||||
* @param[in] en Enable/disable the reference voltage output
|
||||
*/
|
||||
static inline void adc_ll_vref_output(adc_ll_num_t adc, adc_channel_t channel, bool en)
|
||||
{
|
||||
if (adc != ADC_NUM_2) return;
|
||||
|
||||
if (en) {
|
||||
RTCCNTL.bias_conf.dbg_atten = 0; //Check DBG effect outside sleep mode
|
||||
//set dtest (MUX_SEL : 0 -> RTC; 1-> vdd_sar2)
|
||||
RTCCNTL.test_mux.dtest_rtc = 1; //Config test mux to route v_ref to ADC2 Channels
|
||||
//set ent
|
||||
RTCCNTL.test_mux.ent_rtc = 1;
|
||||
//set sar2_en_test
|
||||
SENS.sar_start_force.sar2_en_test = 1;
|
||||
//set sar2 en force
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 1; //Pad bitmap controlled by SW
|
||||
//set en_pad for channels 7,8,9 (bits 0x380)
|
||||
SENS.sar_meas_start2.sar2_en_pad = 1 << channel;
|
||||
} else {
|
||||
RTCCNTL.test_mux.dtest_rtc = 0; //Config test mux to route v_ref to ADC2 Channels
|
||||
//set ent
|
||||
RTCCNTL.test_mux.ent_rtc = 0;
|
||||
//set sar2_en_test
|
||||
SENS.sar_start_force.sar2_en_test = 0;
|
||||
//set sar2 en force
|
||||
SENS.sar_meas_start2.sar2_en_pad_force = 0; //Pad bitmap controlled by SW
|
||||
//set en_pad for channels 7,8,9 (bits 0x380)
|
||||
SENS.sar_meas_start2.sar2_en_pad = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
154
components/hal/esp32/include/hal/can_hal.h
Normal file
154
components/hal/esp32/include/hal/can_hal.h
Normal 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.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The hal is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#warning hal/can_hal.h is deprecated, please use hal/twai_hal.h instead
|
||||
|
||||
#include "hal/twai_hal.h"
|
||||
#include "hal/can_types.h"
|
||||
|
||||
/* ------------------------- Defines and Typedefs --------------------------- */
|
||||
|
||||
//Error active interrupt related
|
||||
#define CAN_HAL_EVENT_BUS_OFF TWAI_HAL_EVENT_BUS_OFF
|
||||
#define CAN_HAL_EVENT_BUS_RECOV_CPLT TWAI_HAL_EVENT_BUS_RECOV_CPLT
|
||||
#define CAN_HAL_EVENT_BUS_RECOV_PROGRESS TWAI_HAL_EVENT_BUS_RECOV_PROGRESS
|
||||
#define CAN_HAL_EVENT_ABOVE_EWL TWAI_HAL_EVENT_ABOVE_EWL
|
||||
#define CAN_HAL_EVENT_BELOW_EWL TWAI_HAL_EVENT_BELOW_EWL
|
||||
#define CAN_HAL_EVENT_ERROR_PASSIVE TWAI_HAL_EVENT_ERROR_PASSIVE
|
||||
#define CAN_HAL_EVENT_ERROR_ACTIVE TWAI_HAL_EVENT_ERROR_ACTIVE
|
||||
#define CAN_HAL_EVENT_BUS_ERR TWAI_HAL_EVENT_BUS_ERR
|
||||
#define CAN_HAL_EVENT_ARB_LOST TWAI_HAL_EVENT_ARB_LOST
|
||||
#define CAN_HAL_EVENT_RX_BUFF_FRAME TWAI_HAL_EVENT_RX_BUFF_FRAME
|
||||
#define CAN_HAL_EVENT_TX_BUFF_FREE TWAI_HAL_EVENT_TX_BUFF_FREE
|
||||
|
||||
typedef twai_hal_context_t can_hal_context_t;
|
||||
|
||||
typedef twai_hal_frame_t can_hal_frame_t;
|
||||
|
||||
/* ---------------------------- Init and Config ----------------------------- */
|
||||
|
||||
static inline bool can_hal_init(can_hal_context_t *hal_ctx){
|
||||
return twai_hal_init(hal_ctx);
|
||||
}
|
||||
|
||||
static inline void can_hal_deinit(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
twai_hal_deinit(hal_ctx);
|
||||
}
|
||||
|
||||
static inline void can_hal_configure(can_hal_context_t *hal_ctx, const can_timing_config_t *t_config, const can_filter_config_t *f_config, uint32_t intr_mask, uint32_t clkout_divider)
|
||||
{
|
||||
twai_hal_configure(hal_ctx, t_config, f_config, intr_mask, clkout_divider);
|
||||
}
|
||||
|
||||
/* -------------------------------- Actions --------------------------------- */
|
||||
|
||||
static inline bool can_hal_start(can_hal_context_t *hal_ctx, can_mode_t mode)
|
||||
{
|
||||
return twai_hal_start(hal_ctx, mode);
|
||||
}
|
||||
|
||||
static inline bool can_hal_stop(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_stop(hal_ctx);
|
||||
}
|
||||
|
||||
static inline bool can_hal_start_bus_recovery(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_start_bus_recovery(hal_ctx);
|
||||
}
|
||||
|
||||
static inline uint32_t can_hal_get_tec(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_get_tec(hal_ctx);
|
||||
}
|
||||
|
||||
static inline uint32_t can_hal_get_rec(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_get_rec(hal_ctx);
|
||||
}
|
||||
|
||||
static inline uint32_t can_hal_get_rx_msg_count(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_get_rx_msg_count(hal_ctx);
|
||||
}
|
||||
|
||||
static inline bool can_hal_check_last_tx_successful(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_check_last_tx_successful(hal_ctx);
|
||||
}
|
||||
|
||||
/* ----------------------------- Event Handling ----------------------------- */
|
||||
|
||||
static inline uint32_t can_hal_decode_interrupt_events(can_hal_context_t *hal_ctx, bool bus_recovering) {
|
||||
return twai_hal_decode_interrupt_events(hal_ctx, bus_recovering);
|
||||
}
|
||||
|
||||
static inline bool can_hal_handle_bus_recov_cplt(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
return twai_hal_handle_bus_recov_cplt(hal_ctx);
|
||||
}
|
||||
|
||||
static inline void can_hal_handle_arb_lost(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
twai_hal_handle_arb_lost(hal_ctx);
|
||||
}
|
||||
|
||||
static inline void can_hal_handle_bus_error(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
twai_hal_handle_bus_error(hal_ctx);
|
||||
}
|
||||
|
||||
static inline void can_hal_handle_bus_off(can_hal_context_t *hal_ctx)
|
||||
{
|
||||
twai_hal_handle_bus_off(hal_ctx);
|
||||
}
|
||||
|
||||
/* ------------------------------- TX and RX -------------------------------- */
|
||||
|
||||
static inline void can_hal_format_frame(const can_message_t *message, can_hal_frame_t *frame)
|
||||
{
|
||||
twai_hal_format_frame(message, frame);
|
||||
}
|
||||
|
||||
static inline void can_hal_parse_frame(can_hal_frame_t *frame, can_message_t *message)
|
||||
{
|
||||
twai_hal_parse_frame(frame, message);
|
||||
}
|
||||
|
||||
static inline void can_hal_set_tx_buffer_and_transmit(can_hal_context_t *hal_ctx, can_hal_frame_t *tx_frame)
|
||||
{
|
||||
twai_hal_set_tx_buffer_and_transmit(hal_ctx, tx_frame);
|
||||
}
|
||||
|
||||
static inline void can_hal_read_rx_buffer_and_clear(can_hal_context_t *hal_ctx, can_hal_frame_t *rx_frame)
|
||||
{
|
||||
twai_hal_read_rx_buffer_and_clear(hal_ctx, rx_frame);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
254
components/hal/esp32/include/hal/can_ll.h
Normal file
254
components/hal/esp32/include/hal/can_ll.h
Normal file
@@ -0,0 +1,254 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The Lowlevel layer for CAN
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#warning hal/can_ll.h is deprecated, please use hal/twai_ll.h instead
|
||||
|
||||
#include "hal/twai_ll.h"
|
||||
#include "hal/can_types.h"
|
||||
#include "soc/can_periph.h"
|
||||
|
||||
/* ------------------------- Defines and Typedefs --------------------------- */
|
||||
|
||||
#define CAN_LL_STATUS_RBS TWAI_LL_STATUS_RBS
|
||||
#define CAN_LL_STATUS_DOS TWAI_LL_STATUS_DOS
|
||||
#define CAN_LL_STATUS_TBS TWAI_LL_STATUS_TBS
|
||||
#define CAN_LL_STATUS_TCS TWAI_LL_STATUS_TCS
|
||||
#define CAN_LL_STATUS_RS TWAI_LL_STATUS_RS
|
||||
#define CAN_LL_STATUS_TS TWAI_LL_STATUS_TS
|
||||
#define CAN_LL_STATUS_ES TWAI_LL_STATUS_ES
|
||||
#define CAN_LL_STATUS_BS TWAI_LL_STATUS_BS
|
||||
|
||||
#define CAN_LL_INTR_RI TWAI_LL_INTR_RI
|
||||
#define CAN_LL_INTR_TI TWAI_LL_INTR_TI
|
||||
#define CAN_LL_INTR_EI TWAI_LL_INTR_EI
|
||||
#define CAN_LL_INTR_EPI TWAI_LL_INTR_EPI
|
||||
#define CAN_LL_INTR_ALI TWAI_LL_INTR_ALI
|
||||
#define CAN_LL_INTR_BEI TWAI_LL_INTR_BEI
|
||||
|
||||
typedef twai_ll_frame_buffer_t can_ll_frame_buffer_t;
|
||||
|
||||
/* ---------------------------- Mode Register ------------------------------- */
|
||||
|
||||
static inline bool can_ll_enter_reset_mode(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_enter_reset_mode(hw);
|
||||
}
|
||||
|
||||
static inline bool can_ll_exit_reset_mode(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_exit_reset_mode(hw);
|
||||
}
|
||||
|
||||
static inline bool can_ll_is_in_reset_mode(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_is_in_reset_mode(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_mode(can_dev_t *hw, can_mode_t mode)
|
||||
{
|
||||
twai_ll_set_mode(hw, mode);
|
||||
}
|
||||
|
||||
/* --------------------------- Command Register ----------------------------- */
|
||||
|
||||
static inline void can_ll_set_cmd_tx(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_tx(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_tx_single_shot(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_tx_single_shot(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_abort_tx(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_abort_tx(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_release_rx_buffer(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_release_rx_buffer(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_clear_data_overrun(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_clear_data_overrun(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_self_rx_request(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_self_rx_request(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_cmd_self_rx_single_shot(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_set_cmd_self_rx_single_shot(hw);
|
||||
}
|
||||
|
||||
/* --------------------------- Status Register ------------------------------ */
|
||||
|
||||
static inline uint32_t can_ll_get_status(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_status(hw);
|
||||
}
|
||||
|
||||
static inline bool can_ll_is_fifo_overrun(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_is_fifo_overrun(hw);
|
||||
}
|
||||
|
||||
static inline bool can_ll_is_last_tx_successful(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_is_last_tx_successful(hw);
|
||||
}
|
||||
|
||||
/* -------------------------- Interrupt Register ---------------------------- */
|
||||
|
||||
static inline uint32_t can_ll_get_and_clear_intrs(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_and_clear_intrs(hw);
|
||||
}
|
||||
|
||||
/* ----------------------- Interrupt Enable Register ------------------------ */
|
||||
|
||||
static inline void can_ll_set_enabled_intrs(can_dev_t *hw, uint32_t intr_mask)
|
||||
{
|
||||
twai_ll_set_enabled_intrs(hw, intr_mask);
|
||||
}
|
||||
|
||||
/* ------------------------ Bus Timing Registers --------------------------- */
|
||||
|
||||
static inline void can_ll_set_bus_timing(can_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling)
|
||||
{
|
||||
twai_ll_set_bus_timing(hw, brp, sjw, tseg1, tseg2, triple_sampling);
|
||||
}
|
||||
|
||||
/* ----------------------------- ALC Register ------------------------------- */
|
||||
|
||||
static inline void can_ll_clear_arb_lost_cap(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_clear_arb_lost_cap(hw);
|
||||
}
|
||||
|
||||
/* ----------------------------- ECC Register ------------------------------- */
|
||||
|
||||
static inline void can_ll_clear_err_code_cap(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_clear_err_code_cap(hw);
|
||||
}
|
||||
|
||||
/* ----------------------------- EWL Register ------------------------------- */
|
||||
|
||||
static inline void can_ll_set_err_warn_lim(can_dev_t *hw, uint32_t ewl)
|
||||
{
|
||||
twai_ll_set_err_warn_lim(hw, ewl);
|
||||
}
|
||||
|
||||
static inline uint32_t can_ll_get_err_warn_lim(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_err_warn_lim(hw);
|
||||
}
|
||||
|
||||
/* ------------------------ RX Error Count Register ------------------------- */
|
||||
|
||||
static inline uint32_t can_ll_get_rec(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_rec(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_rec(can_dev_t *hw, uint32_t rec)
|
||||
{
|
||||
twai_ll_set_rec(hw, rec);
|
||||
}
|
||||
|
||||
/* ------------------------ TX Error Count Register ------------------------- */
|
||||
|
||||
static inline uint32_t can_ll_get_tec(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_tec(hw);
|
||||
}
|
||||
|
||||
static inline void can_ll_set_tec(can_dev_t *hw, uint32_t tec)
|
||||
{
|
||||
twai_ll_set_tec(hw, tec);
|
||||
}
|
||||
|
||||
/* ---------------------- Acceptance Filter Registers ----------------------- */
|
||||
|
||||
static inline void can_ll_set_acc_filter(can_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
|
||||
{
|
||||
twai_ll_set_acc_filter(hw, code, mask, single_filter);
|
||||
}
|
||||
|
||||
/* ------------------------- TX/RX Buffer Registers ------------------------- */
|
||||
|
||||
static inline void can_ll_set_tx_buffer(can_dev_t *hw, can_ll_frame_buffer_t *tx_frame)
|
||||
{
|
||||
twai_ll_set_tx_buffer(hw, tx_frame);
|
||||
}
|
||||
|
||||
static inline void can_ll_get_rx_buffer(can_dev_t *hw, can_ll_frame_buffer_t *rx_frame)
|
||||
{
|
||||
twai_ll_get_rx_buffer(hw, rx_frame);
|
||||
}
|
||||
|
||||
static inline void can_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const uint8_t *data,
|
||||
uint32_t flags, can_ll_frame_buffer_t *tx_frame)
|
||||
{
|
||||
twai_ll_format_frame_buffer(id, dlc, data, flags, tx_frame);
|
||||
}
|
||||
|
||||
static inline void can_ll_prase_frame_buffer(can_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
|
||||
uint8_t *data, uint32_t *flags)
|
||||
{
|
||||
twai_ll_prase_frame_buffer(rx_frame, id, dlc, data, flags);
|
||||
}
|
||||
|
||||
/* ----------------------- RX Message Count Register ------------------------ */
|
||||
|
||||
static inline uint32_t can_ll_get_rx_msg_count(can_dev_t *hw)
|
||||
{
|
||||
return twai_ll_get_rx_msg_count(hw);
|
||||
}
|
||||
|
||||
/* ------------------------- Clock Divider Register ------------------------- */
|
||||
|
||||
static inline void can_ll_set_clkout(can_dev_t *hw, uint32_t divider)
|
||||
{
|
||||
twai_ll_set_clkout(hw, divider);
|
||||
}
|
||||
|
||||
static inline void can_ll_enable_extended_reg_layout(can_dev_t *hw)
|
||||
{
|
||||
twai_ll_enable_extended_reg_layout(hw);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
68
components/hal/esp32/include/hal/can_types.h
Normal file
68
components/hal/esp32/include/hal/can_types.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#warning hal/can_types.h is deprecated, please use hal/twai_types.h instead
|
||||
|
||||
#include "hal/twai_types.h"
|
||||
|
||||
/* ---------------------------- Compatibility ------------------------------- */
|
||||
|
||||
#define CAN_EXTD_ID_MASK TWAI_EXTD_ID_MASK
|
||||
#define CAN_STD_ID_MASK TWAI_STD_ID_MASK
|
||||
#define CAN_FRAME_MAX_DLC TWAI_FRAME_MAX_DLC
|
||||
#define CAN_FRAME_EXTD_ID_LEN_BYTES TWAI_FRAME_EXTD_ID_LEN_BYTES
|
||||
#define CAN_FRAME_STD_ID_LEN_BYTES TWAI_FRAME_STD_ID_LEN_BYTES
|
||||
#define CAN_ERR_PASS_THRESH TWAI_ERR_PASS_THRESH
|
||||
|
||||
#define CAN_MSG_FLAG_NONE TWAI_MSG_FLAG_NONE
|
||||
#define CAN_MSG_FLAG_EXTD TWAI_MSG_FLAG_EXTD
|
||||
#define CAN_MSG_FLAG_RTR TWAI_MSG_FLAG_RTR
|
||||
#define CAN_MSG_FLAG_SS TWAI_MSG_FLAG_SS
|
||||
#define CAN_MSG_FLAG_SELF TWAI_MSG_FLAG_SELF
|
||||
#define CAN_MSG_FLAG_DLC_NON_COMP TWAI_MSG_FLAG_DLC_NON_COMP
|
||||
|
||||
#if (TWAI_BRP_MAX > 128) || (CONFIG_ESP32_REV_MIN >= 2)
|
||||
#define CAN_TIMING_CONFIG_12_5KBITS() TWAI_TIMING_CONFIG_12_5KBITS()
|
||||
#define CAN_TIMING_CONFIG_16KBITS() TWAI_TIMING_CONFIG_16KBITS()
|
||||
#define CAN_TIMING_CONFIG_20KBITS() TWAI_TIMING_CONFIG_20KBITS()
|
||||
#endif
|
||||
#define CAN_TIMING_CONFIG_25KBITS() TWAI_TIMING_CONFIG_25KBITS()
|
||||
#define CAN_TIMING_CONFIG_50KBITS() TWAI_TIMING_CONFIG_50KBITS()
|
||||
#define CAN_TIMING_CONFIG_100KBITS() TWAI_TIMING_CONFIG_100KBITS()
|
||||
#define CAN_TIMING_CONFIG_125KBITS() TWAI_TIMING_CONFIG_125KBITS()
|
||||
#define CAN_TIMING_CONFIG_250KBITS() TWAI_TIMING_CONFIG_250KBITS()
|
||||
#define CAN_TIMING_CONFIG_500KBITS() TWAI_TIMING_CONFIG_500KBITS()
|
||||
#define CAN_TIMING_CONFIG_800KBITS() TWAI_TIMING_CONFIG_800KBITS()
|
||||
#define CAN_TIMING_CONFIG_1MBITS() TWAI_TIMING_CONFIG_1MBITS()
|
||||
|
||||
#define CAN_FILTER_CONFIG_ACCEPT_ALL() TWAI_FILTER_CONFIG_ACCEPT_ALL()
|
||||
|
||||
typedef twai_mode_t can_mode_t;
|
||||
#define CAN_MODE_NORMAL TWAI_MODE_NORMAL
|
||||
#define CAN_MODE_NO_ACK TWAI_MODE_NO_ACK
|
||||
#define CAN_MODE_LISTEN_ONLY TWAI_MODE_LISTEN_ONLY
|
||||
|
||||
typedef twai_message_t can_message_t;
|
||||
typedef twai_timing_config_t can_timing_config_t;
|
||||
typedef twai_filter_config_t can_filter_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
271
components/hal/esp32/include/hal/clk_gate_ll.h
Normal file
271
components/hal/esp32/include/hal/clk_gate_ll.h
Normal file
@@ -0,0 +1,271 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/dport_access.h"
|
||||
|
||||
static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
|
||||
{
|
||||
switch (periph) {
|
||||
case PERIPH_LEDC_MODULE:
|
||||
return DPORT_LEDC_CLK_EN;
|
||||
case PERIPH_UART0_MODULE:
|
||||
return DPORT_UART_CLK_EN;
|
||||
case PERIPH_UART1_MODULE:
|
||||
return DPORT_UART1_CLK_EN;
|
||||
case PERIPH_UART2_MODULE:
|
||||
return DPORT_UART2_CLK_EN;
|
||||
case PERIPH_I2C0_MODULE:
|
||||
return DPORT_I2C_EXT0_CLK_EN;
|
||||
case PERIPH_I2C1_MODULE:
|
||||
return DPORT_I2C_EXT1_CLK_EN;
|
||||
case PERIPH_I2S0_MODULE:
|
||||
return DPORT_I2S0_CLK_EN;
|
||||
case PERIPH_I2S1_MODULE:
|
||||
return DPORT_I2S1_CLK_EN;
|
||||
case PERIPH_TIMG0_MODULE:
|
||||
return DPORT_TIMERGROUP_CLK_EN;
|
||||
case PERIPH_TIMG1_MODULE:
|
||||
return DPORT_TIMERGROUP1_CLK_EN;
|
||||
case PERIPH_PWM0_MODULE:
|
||||
return DPORT_PWM0_CLK_EN;
|
||||
case PERIPH_PWM1_MODULE:
|
||||
return DPORT_PWM1_CLK_EN;
|
||||
case PERIPH_PWM2_MODULE:
|
||||
return DPORT_PWM2_CLK_EN;
|
||||
case PERIPH_PWM3_MODULE:
|
||||
return DPORT_PWM3_CLK_EN;
|
||||
case PERIPH_UHCI0_MODULE:
|
||||
return DPORT_UHCI0_CLK_EN;
|
||||
case PERIPH_UHCI1_MODULE:
|
||||
return DPORT_UHCI1_CLK_EN;
|
||||
case PERIPH_RMT_MODULE:
|
||||
return DPORT_RMT_CLK_EN;
|
||||
case PERIPH_PCNT_MODULE:
|
||||
return DPORT_PCNT_CLK_EN;
|
||||
case PERIPH_SPI_MODULE:
|
||||
return DPORT_SPI01_CLK_EN;
|
||||
case PERIPH_HSPI_MODULE:
|
||||
return DPORT_SPI2_CLK_EN;
|
||||
case PERIPH_VSPI_MODULE:
|
||||
return DPORT_SPI3_CLK_EN;
|
||||
case PERIPH_SPI_DMA_MODULE:
|
||||
return DPORT_SPI_DMA_CLK_EN;
|
||||
case PERIPH_SDMMC_MODULE:
|
||||
return DPORT_WIFI_CLK_SDIO_HOST_EN;
|
||||
case PERIPH_SDIO_SLAVE_MODULE:
|
||||
return DPORT_WIFI_CLK_SDIOSLAVE_EN;
|
||||
case PERIPH_TWAI_MODULE:
|
||||
return DPORT_TWAI_CLK_EN;
|
||||
case PERIPH_EMAC_MODULE:
|
||||
return DPORT_WIFI_CLK_EMAC_EN;
|
||||
case PERIPH_RNG_MODULE:
|
||||
return DPORT_WIFI_CLK_RNG_EN;
|
||||
case PERIPH_WIFI_MODULE:
|
||||
return DPORT_WIFI_CLK_WIFI_EN_M;
|
||||
case PERIPH_BT_MODULE:
|
||||
return DPORT_WIFI_CLK_BT_EN_M;
|
||||
case PERIPH_WIFI_BT_COMMON_MODULE:
|
||||
return DPORT_WIFI_CLK_WIFI_BT_COMMON_M;
|
||||
case PERIPH_BT_BASEBAND_MODULE:
|
||||
return DPORT_BT_BASEBAND_EN;
|
||||
case PERIPH_BT_LC_MODULE:
|
||||
return DPORT_BT_LC_EN;
|
||||
case PERIPH_AES_MODULE:
|
||||
return DPORT_PERI_EN_AES;
|
||||
case PERIPH_SHA_MODULE:
|
||||
return DPORT_PERI_EN_SHA;
|
||||
case PERIPH_RSA_MODULE:
|
||||
return DPORT_PERI_EN_RSA;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable)
|
||||
{
|
||||
switch (periph) {
|
||||
case PERIPH_LEDC_MODULE:
|
||||
return DPORT_LEDC_RST;
|
||||
case PERIPH_UART0_MODULE:
|
||||
return DPORT_UART_RST;
|
||||
case PERIPH_UART1_MODULE:
|
||||
return DPORT_UART1_RST;
|
||||
case PERIPH_UART2_MODULE:
|
||||
return DPORT_UART2_RST;
|
||||
case PERIPH_I2C0_MODULE:
|
||||
return DPORT_I2C_EXT0_RST;
|
||||
case PERIPH_I2C1_MODULE:
|
||||
return DPORT_I2C_EXT1_RST;
|
||||
case PERIPH_I2S0_MODULE:
|
||||
return DPORT_I2S0_RST;
|
||||
case PERIPH_I2S1_MODULE:
|
||||
return DPORT_I2S1_RST;
|
||||
case PERIPH_TIMG0_MODULE:
|
||||
return DPORT_TIMERGROUP_RST;
|
||||
case PERIPH_TIMG1_MODULE:
|
||||
return DPORT_TIMERGROUP1_RST;
|
||||
case PERIPH_PWM0_MODULE:
|
||||
return DPORT_PWM0_RST;
|
||||
case PERIPH_PWM1_MODULE:
|
||||
return DPORT_PWM1_RST;
|
||||
case PERIPH_PWM2_MODULE:
|
||||
return DPORT_PWM2_RST;
|
||||
case PERIPH_PWM3_MODULE:
|
||||
return DPORT_PWM3_RST;
|
||||
case PERIPH_UHCI0_MODULE:
|
||||
return DPORT_UHCI0_RST;
|
||||
case PERIPH_UHCI1_MODULE:
|
||||
return DPORT_UHCI1_RST;
|
||||
case PERIPH_RMT_MODULE:
|
||||
return DPORT_RMT_RST;
|
||||
case PERIPH_PCNT_MODULE:
|
||||
return DPORT_PCNT_RST;
|
||||
case PERIPH_SPI_MODULE:
|
||||
return DPORT_SPI01_RST;
|
||||
case PERIPH_HSPI_MODULE:
|
||||
return DPORT_SPI2_RST;
|
||||
case PERIPH_VSPI_MODULE:
|
||||
return DPORT_SPI3_RST;
|
||||
case PERIPH_SPI_DMA_MODULE:
|
||||
return DPORT_SPI_DMA_RST;
|
||||
case PERIPH_SDMMC_MODULE:
|
||||
return DPORT_SDIO_HOST_RST;
|
||||
case PERIPH_SDIO_SLAVE_MODULE:
|
||||
return DPORT_SDIO_RST;
|
||||
case PERIPH_TWAI_MODULE:
|
||||
return DPORT_TWAI_RST;
|
||||
case PERIPH_EMAC_MODULE:
|
||||
return DPORT_EMAC_RST;
|
||||
case PERIPH_AES_MODULE:
|
||||
if (enable == true) {
|
||||
// Clear reset on digital signature & secure boot units, otherwise AES unit is held in reset also.
|
||||
return (DPORT_PERI_EN_AES | DPORT_PERI_EN_DIGITAL_SIGNATURE | DPORT_PERI_EN_SECUREBOOT);
|
||||
} else {
|
||||
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
|
||||
return DPORT_PERI_EN_AES;
|
||||
}
|
||||
case PERIPH_SHA_MODULE:
|
||||
if (enable == true) {
|
||||
// Clear reset on secure boot, otherwise SHA is held in reset
|
||||
return (DPORT_PERI_EN_SHA | DPORT_PERI_EN_SECUREBOOT);
|
||||
} else {
|
||||
// Don't assert reset on secure boot, otherwise AES is held in reset
|
||||
return DPORT_PERI_EN_SHA;
|
||||
}
|
||||
case PERIPH_RSA_MODULE:
|
||||
if (enable == true) {
|
||||
// Also clear reset on digital signature, otherwise RSA is held in reset
|
||||
return (DPORT_PERI_EN_RSA | DPORT_PERI_EN_DIGITAL_SIGNATURE);
|
||||
} else {
|
||||
// Don't reset digital signature unit, as this resets AES also
|
||||
return DPORT_PERI_EN_RSA;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
|
||||
{
|
||||
switch (periph) {
|
||||
case PERIPH_AES_MODULE:
|
||||
case PERIPH_SHA_MODULE:
|
||||
case PERIPH_RSA_MODULE:
|
||||
return DPORT_PERI_CLK_EN_REG;
|
||||
case PERIPH_SDMMC_MODULE:
|
||||
case PERIPH_SDIO_SLAVE_MODULE:
|
||||
case PERIPH_EMAC_MODULE:
|
||||
case PERIPH_RNG_MODULE:
|
||||
case PERIPH_WIFI_MODULE:
|
||||
case PERIPH_BT_MODULE:
|
||||
case PERIPH_WIFI_BT_COMMON_MODULE:
|
||||
case PERIPH_BT_BASEBAND_MODULE:
|
||||
case PERIPH_BT_LC_MODULE:
|
||||
return DPORT_WIFI_CLK_EN_REG;
|
||||
default:
|
||||
return DPORT_PERIP_CLK_EN_REG;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
|
||||
{
|
||||
switch (periph) {
|
||||
case PERIPH_AES_MODULE:
|
||||
case PERIPH_SHA_MODULE:
|
||||
case PERIPH_RSA_MODULE:
|
||||
return DPORT_PERI_RST_EN_REG;
|
||||
case PERIPH_SDMMC_MODULE:
|
||||
case PERIPH_SDIO_SLAVE_MODULE:
|
||||
case PERIPH_EMAC_MODULE:
|
||||
case PERIPH_RNG_MODULE:
|
||||
case PERIPH_WIFI_MODULE:
|
||||
case PERIPH_BT_MODULE:
|
||||
case PERIPH_WIFI_BT_COMMON_MODULE:
|
||||
case PERIPH_BT_BASEBAND_MODULE:
|
||||
case PERIPH_BT_LC_MODULE:
|
||||
return DPORT_CORE_RST_EN_REG;
|
||||
default:
|
||||
return DPORT_PERIP_RST_EN_REG;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void periph_ll_enable_clk_clear_rst(periph_module_t periph)
|
||||
{
|
||||
DPORT_SET_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
|
||||
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, true));
|
||||
}
|
||||
|
||||
static inline void periph_ll_disable_clk_set_rst(periph_module_t periph)
|
||||
{
|
||||
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
|
||||
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
|
||||
}
|
||||
|
||||
static inline void IRAM_ATTR periph_ll_wifi_bt_module_enable_clk_clear_rst(void)
|
||||
{
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
|
||||
}
|
||||
|
||||
static inline void IRAM_ATTR periph_ll_wifi_bt_module_disable_clk_set_rst(void)
|
||||
{
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
|
||||
}
|
||||
|
||||
static inline void periph_ll_reset(periph_module_t periph)
|
||||
{
|
||||
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
|
||||
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
|
||||
}
|
||||
|
||||
static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
|
||||
{
|
||||
return DPORT_REG_GET_BIT(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)) == 0 &&
|
||||
DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
178
components/hal/esp32/include/hal/cpu_ll.h
Normal file
178
components/hal/esp32/include/hal/cpu_ll.h
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "soc/cpu_caps.h"
|
||||
|
||||
#include "xt_instr_macros.h"
|
||||
#include "xtensa/config/specreg.h"
|
||||
#include "xtensa/config/extreg.h"
|
||||
#include "esp_bit_defs.h"
|
||||
#include "xtensa/config/core.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int IRAM_ATTR cpu_ll_get_core_id(void)
|
||||
{
|
||||
uint32_t id;
|
||||
asm volatile (
|
||||
"rsr.prid %0\n"
|
||||
"extui %0,%0,13,1"
|
||||
:"=r"(id));
|
||||
return (int) id;
|
||||
}
|
||||
|
||||
static inline uint32_t cpu_ll_get_cycle_count(void)
|
||||
{
|
||||
uint32_t result;
|
||||
RSR(CCOUNT, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void* cpu_ll_get_sp(void)
|
||||
{
|
||||
void *sp;
|
||||
asm volatile ("mov %0, sp;" : "=r" (sp));
|
||||
return sp;
|
||||
}
|
||||
|
||||
static inline void cpu_ll_init_hwloop(void)
|
||||
{
|
||||
#if XCHAL_ERRATUM_572
|
||||
uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
|
||||
WSR(MEMCTL, memctl);
|
||||
#endif // XCHAL_ERRATUM_572
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
{
|
||||
uint32_t en;
|
||||
|
||||
// Set the break address register to the appropriate PC
|
||||
if (id) {
|
||||
WSR(IBREAKA_1, pc);
|
||||
} else {
|
||||
WSR(IBREAKA_0, pc);
|
||||
}
|
||||
|
||||
// Enable the breakpoint using the break enable register
|
||||
RSR(IBREAKENABLE, en);
|
||||
en |= BIT(id);
|
||||
WSR(IBREAKENABLE, en);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_clear_breakpoint(int id)
|
||||
{
|
||||
uint32_t en = 0;
|
||||
uint32_t pc = 0;
|
||||
|
||||
// Set the break address register to the appropriate PC
|
||||
if (id) {
|
||||
WSR(IBREAKA_1, pc);
|
||||
} else {
|
||||
WSR(IBREAKA_0, pc);
|
||||
}
|
||||
|
||||
// Enable the breakpoint using the break enable register
|
||||
RSR(IBREAKENABLE, en);
|
||||
en &= ~BIT(id);
|
||||
WSR(IBREAKENABLE, en);
|
||||
}
|
||||
|
||||
static inline uint32_t cpu_ll_ptr_to_pc(const void* addr)
|
||||
{
|
||||
return ((uint32_t) addr);
|
||||
}
|
||||
|
||||
static inline void* cpu_ll_pc_to_ptr(uint32_t pc)
|
||||
{
|
||||
return (void*) ((pc & 0x3fffffffU) | 0x40000000U);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_watchpoint(int id,
|
||||
const void* addr,
|
||||
size_t size,
|
||||
bool on_read,
|
||||
bool on_write)
|
||||
{
|
||||
uint32_t dbreakc = 0x3F;
|
||||
|
||||
//We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
|
||||
for (int x = 0; x < 7; x++) {
|
||||
if (size == (size_t)(1 << x)) {
|
||||
break;
|
||||
}
|
||||
dbreakc <<= 1;
|
||||
}
|
||||
|
||||
dbreakc = (dbreakc & 0x3F);
|
||||
|
||||
if (on_read) {
|
||||
dbreakc |= BIT(30);
|
||||
}
|
||||
|
||||
if (on_write) {
|
||||
dbreakc |= BIT(31);
|
||||
}
|
||||
|
||||
// Write the break address register and the size to control
|
||||
// register.
|
||||
if (id) {
|
||||
WSR(DBREAKA_1, (uint32_t) addr);
|
||||
WSR(DBREAKC_1, dbreakc);
|
||||
} else {
|
||||
WSR(DBREAKA_0, (uint32_t) addr);
|
||||
WSR(DBREAKC_0, dbreakc);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_ll_clear_watchpoint(int id)
|
||||
{
|
||||
// Clear both break address register and control register
|
||||
if (id) {
|
||||
WSR(DBREAKA_1, 0);
|
||||
WSR(DBREAKC_1, 0);
|
||||
} else {
|
||||
WSR(DBREAKA_0, 0);
|
||||
WSR(DBREAKC_0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
uint32_t dcr = 0;
|
||||
uint32_t reg = DSRSET;
|
||||
RER(reg, dcr);
|
||||
return (dcr&0x1);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_break(void)
|
||||
{
|
||||
__asm__ ("break 0,0");
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_vecbase(const void* vecbase)
|
||||
{
|
||||
asm volatile ("wsr %0, vecbase" :: "r" (vecbase));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
198
components/hal/esp32/include/hal/dac_ll.h
Normal file
198
components/hal/esp32/include/hal/dac_ll.h
Normal file
@@ -0,0 +1,198 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "soc/dac_periph.h"
|
||||
#include "hal/dac_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Power on dac module and start output voltage.
|
||||
*
|
||||
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_on(dac_channel_t channel)
|
||||
{
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 1;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Power done dac module and stop output voltage.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
*/
|
||||
static inline void dac_ll_power_down(dac_channel_t channel)
|
||||
{
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 0;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output voltage with value (8 bit).
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param value Output value. Value range: 0 ~ 255.
|
||||
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
|
||||
*/
|
||||
static inline void dac_ll_update_output_value(dac_channel_t channel, uint8_t value)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
|
||||
RTCIO.pad_dac[channel].dac = value;
|
||||
} else if (channel == DAC_CHANNEL_2) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
|
||||
RTCIO.pad_dac[channel].dac = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the synchronization operation function of ADC1 and DAC.
|
||||
*
|
||||
* @note If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage.
|
||||
*
|
||||
* @param enable Enable or disable adc and dac synchronization function.
|
||||
*/
|
||||
static inline void dac_ll_rtc_sync_by_adc(bool enable)
|
||||
{
|
||||
SENS.sar_meas_ctrl2.sar1_dac_xpd_fsm = enable;
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* DAC cosine wave generator API's */
|
||||
/************************************/
|
||||
/**
|
||||
* Enable cosine wave generator output.
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_enable(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cosine wave generator output.
|
||||
*/
|
||||
static inline void dac_ll_cw_generator_disable(void)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.sw_tone_en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the cosine wave generator of DAC channel.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param enable
|
||||
*/
|
||||
static inline void dac_ll_cw_set_channel(dac_channel_t channel, bool enable)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = enable;
|
||||
} else if (channel == DAC_CHANNEL_2) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set frequency of cosine wave generator output.
|
||||
*
|
||||
* @note We know that CLK8M is about 8M, but don't know the actual value. so this freq have limited error.
|
||||
* @param freq_hz CW generator frequency. Range: 130(130Hz) ~ 55000(100KHz).
|
||||
*/
|
||||
static inline void dac_ll_cw_set_freq(uint32_t freq)
|
||||
{
|
||||
uint32_t sw_freq = freq * 0xFFFF / RTC_FAST_CLK_FREQ_APPROX;
|
||||
SENS.sar_dac_ctrl1.sw_fstep = (sw_freq > 0xFFFF) ? 0xFFFF : sw_freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amplitude of the cosine wave generator output.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param scale The multiple of the amplitude. The max amplitude is VDD3P3_RTC.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_scale(dac_channel_t channel, dac_cw_scale_t scale)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_scale1 = scale;
|
||||
} else if (channel == DAC_CHANNEL_2) {
|
||||
SENS.sar_dac_ctrl2.dac_scale2 = scale;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the phase of the cosine wave generator output.
|
||||
*
|
||||
* @param channel DAC channel num.
|
||||
* @param scale Phase value.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_phase(dac_channel_t channel, dac_cw_phase_t phase)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
SENS.sar_dac_ctrl2.dac_inv1 = phase;
|
||||
} else if (channel == DAC_CHANNEL_2) {
|
||||
SENS.sar_dac_ctrl2.dac_inv2 = phase;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the voltage value of the DC component of the cosine wave generator output.
|
||||
*
|
||||
* @note The DC offset setting should be after phase setting.
|
||||
* @note Unreasonable settings can cause the signal to be oversaturated.
|
||||
* @param channel DAC channel num.
|
||||
* @param offset DC value. Range: -128 ~ 127.
|
||||
*/
|
||||
static inline void dac_ll_cw_set_dc_offset(dac_channel_t channel, int8_t offset)
|
||||
{
|
||||
if (channel == DAC_CHANNEL_1) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv1 == DAC_CW_PHASE_180) {
|
||||
offset = 0 - offset;
|
||||
}
|
||||
SENS.sar_dac_ctrl2.dac_dc1 = offset ? offset : (-128 - offset);
|
||||
} else if (channel == DAC_CHANNEL_2) {
|
||||
if (SENS.sar_dac_ctrl2.dac_inv2 == DAC_CW_PHASE_180) {
|
||||
offset = 0 - offset;
|
||||
}
|
||||
SENS.sar_dac_ctrl2.dac_dc2 = offset ? offset : (-128 - offset);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* DAC DMA API's */
|
||||
/************************************/
|
||||
/**
|
||||
* Enable/disable DAC output data from I2S DMA.
|
||||
* I2S_CLK connect to DAC_CLK, I2S_DATA_OUT connect to DAC_DATA.
|
||||
*/
|
||||
static inline void dac_ll_digi_enable_dma(bool enable)
|
||||
{
|
||||
SENS.sar_dac_ctrl1.dac_dig_force = enable;
|
||||
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
410
components/hal/esp32/include/hal/emac.h
Normal file
410
components/hal/esp32/include/hal/emac.h
Normal file
@@ -0,0 +1,410 @@
|
||||
// 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 "esp_err.h"
|
||||
#include "soc/emac_dma_struct.h"
|
||||
#include "soc/emac_mac_struct.h"
|
||||
#include "soc/emac_ext_struct.h"
|
||||
|
||||
#define EMAC_MEDIA_INTERFACE_MII (0)
|
||||
#define EMAC_MEDIA_INTERFACE_RMII (1)
|
||||
|
||||
#define EMAC_WATCHDOG_ENABLE (0)
|
||||
#define EMAC_WATCHDOG_DISABLE (1)
|
||||
|
||||
#define EMAC_JABBER_ENABLE (0)
|
||||
#define EMAC_JABBER_DISABLE (1)
|
||||
|
||||
#define EMAC_INTERFRAME_GAP_96BIT (0)
|
||||
#define EMAC_INTERFRAME_GAP_88BIT (1)
|
||||
#define EMAC_INTERFRAME_GAP_80BIT (2)
|
||||
#define EMAC_INTERFRAME_GAP_72BIT (3)
|
||||
#define EMAC_INTERFRAME_GAP_64BIT (4)
|
||||
#define EMAC_INTERFRAME_GAP_56BIT (5)
|
||||
#define EMAC_INTERFRAME_GAP_48BIT (6)
|
||||
#define EMAC_INTERFRAME_GAP_40BIT (7)
|
||||
|
||||
#define EMAC_CARRIERSENSE_ENABLE (0)
|
||||
#define EMAC_CARRIERSENSE_DISABLE (1)
|
||||
|
||||
#define EMAC_PORT_1000MBPS (0)
|
||||
#define EMAC_PORT_10_100MBPS (1)
|
||||
|
||||
#define EMAC_SPEED_10M (0)
|
||||
#define EMAC_SPEED_100M (1)
|
||||
|
||||
#define EMAC_RECEIVE_OWN_ENABLE (0)
|
||||
#define EMAC_RECEIVE_OWN_DISABLE (1)
|
||||
|
||||
#define EMAC_LOOPBACK_DISABLE (0)
|
||||
#define EMAC_LOOPBACK_ENABLE (1)
|
||||
|
||||
#define EMAC_DUPLEX_HALF (0)
|
||||
#define EMAC_DUPLEX_FULL (1)
|
||||
|
||||
#define EMAC_CHECKSUM_SW (0)
|
||||
#define EMAC_CHECKSUM_HW (1)
|
||||
|
||||
#define EMAC_RETRY_TRANSMISSION_ENABLE (0)
|
||||
#define EMAC_RETRY_TRANSMISSION_DISABLE (1)
|
||||
|
||||
#define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0)
|
||||
#define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1)
|
||||
|
||||
#define EMAC_BACKOFF_LIMIT_10 (0)
|
||||
#define EMAC_BACKOFF_LIMIT_8 (1)
|
||||
#define EMAC_BACKOFF_LIMIT_4 (2)
|
||||
#define EMAC_BACKOFF_LIMIT_1 (3)
|
||||
|
||||
#define EMAC_DEFERRAL_CHECK_DISABLE (0)
|
||||
#define EMAC_DEFERRAL_CHECK_ENABLE (1)
|
||||
|
||||
#define EMAC_PREAMBLE_LENGTH_7 (0)
|
||||
#define EMAC_PREAMBLE_LENGTH_5 (1)
|
||||
#define EMAC_PREAMBLE_LENGTH_3 (2)
|
||||
|
||||
#define EMAC_RECEIVE_ALL_DISABLE (0)
|
||||
#define EMAC_RECEIVE_ALL_ENABLE (1)
|
||||
|
||||
#define EMAC_SOURCE_ADDR_FILTER_DISABLE (0)
|
||||
#define EMAC_SOURCE_ADDR_FILTER_NORMAL (2)
|
||||
#define EMAC_SOURCE_ADDR_FILTER_INVERSE (3)
|
||||
|
||||
#define EMAC_CONTROL_FRAME_BLOCKALL (0)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDALL (2)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDFILT (3)
|
||||
|
||||
#define EMAC_RECEPT_BROADCAST_ENABLE (0)
|
||||
#define EMAC_RECEPT_BROADCAST_DISABLE (1)
|
||||
|
||||
#define EMAC_DEST_ADDR_FILTER_NORMAL (0)
|
||||
#define EMAC_DEST_ADDR_FILTER_INVERSE (1)
|
||||
|
||||
#define EMAC_PROMISCUOUS_DISABLE (0)
|
||||
#define EMAC_PROMISCUOUS_ENABLE (1)
|
||||
|
||||
#define EMAC_PAUSE_TIME 0x1648
|
||||
|
||||
#define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0)
|
||||
#define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1)
|
||||
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256
|
||||
|
||||
#define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0)
|
||||
#define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0)
|
||||
#define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0)
|
||||
#define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1)
|
||||
|
||||
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0)
|
||||
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0)
|
||||
#define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1)
|
||||
|
||||
#define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0)
|
||||
#define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0)
|
||||
#define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7)
|
||||
|
||||
#define EMAC_FORWARD_ERROR_FRAME_DISABLE (0)
|
||||
#define EMAC_FORWARD_ERROR_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0)
|
||||
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3)
|
||||
|
||||
#define EMAC_OPERATE_SECOND_FRAME_DISABLE (0)
|
||||
#define EMAC_OPERATE_SECOND_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_MIXED_BURST_DISABLE (0)
|
||||
#define EMAC_MIXED_BURST_ENABLE (1)
|
||||
|
||||
#define EMAC_ADDR_ALIGN_BEATS_DISABLE (0)
|
||||
#define EMAC_ADDR_ALIGN_BEATS_ENABLE (1)
|
||||
|
||||
#define EMAC_UNUSE_SEPARATE_PBL (0)
|
||||
#define EMAC_USE_SEPARATE_PBL (1)
|
||||
|
||||
#define EMAC_DMA_BURST_LENGTH_1BEAT (1)
|
||||
#define EMAC_DMA_BURST_LENGTH_2BEAT (2)
|
||||
#define EMAC_DMA_BURST_LENGTH_4BEAT (4)
|
||||
#define EMAC_DMA_BURST_LENGTH_8BEAT (8)
|
||||
#define EMAC_DMA_BURST_LENGTH_16BEAT (16)
|
||||
#define EMAC_DMA_BURST_LENGTH_32BEAT (32)
|
||||
|
||||
#define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0)
|
||||
#define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1)
|
||||
|
||||
#define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0)
|
||||
#define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1)
|
||||
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
|
||||
|
||||
/**
|
||||
* @brief Ethernet DMA TX Descriptor
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
volatile union {
|
||||
struct {
|
||||
uint32_t Deferred : 1; /*!< MAC defers before transmission */
|
||||
uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */
|
||||
uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */
|
||||
uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */
|
||||
uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */
|
||||
uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */
|
||||
uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */
|
||||
uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */
|
||||
uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */
|
||||
uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */
|
||||
uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */
|
||||
uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */
|
||||
uint32_t ErrSummary : 1; /*!< Error Summary */
|
||||
uint32_t IPHeadErr : 1; /*!< IP Header Error */
|
||||
uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */
|
||||
uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */
|
||||
uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */
|
||||
uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */
|
||||
uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */
|
||||
uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */
|
||||
uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */
|
||||
uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */
|
||||
uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */
|
||||
uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */
|
||||
uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */
|
||||
uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */
|
||||
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
|
||||
};
|
||||
uint32_t Value;
|
||||
} TDES0;
|
||||
union {
|
||||
struct {
|
||||
uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */
|
||||
uint32_t Reserved : 3; /*!< Reserved */
|
||||
uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */
|
||||
uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */
|
||||
};
|
||||
uint32_t Value;
|
||||
} TDES1;
|
||||
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
|
||||
uint32_t Reserved1; /*!< Reserved */
|
||||
uint32_t Reserved2; /*!< Reserved */
|
||||
uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */
|
||||
uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */
|
||||
} eth_dma_tx_descriptor_t;
|
||||
#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */
|
||||
#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */
|
||||
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */
|
||||
#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */
|
||||
|
||||
_Static_assert(sizeof(eth_dma_tx_descriptor_t) == 32, "eth_dma_tx_descriptor_t should occupy 32 bytes in memory");
|
||||
|
||||
/**
|
||||
* @brief Ethernet DMA RX Descriptor
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
volatile union {
|
||||
struct {
|
||||
uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */
|
||||
uint32_t CRCErr : 1; /*!< CRC error occurred on frame */
|
||||
uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */
|
||||
uint32_t ReceiveErr : 1; /*!< Receive error */
|
||||
uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */
|
||||
uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */
|
||||
uint32_t LateCollision : 1; /*!< Late collision occurred during reception */
|
||||
uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */
|
||||
uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */
|
||||
uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */
|
||||
uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */
|
||||
uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */
|
||||
uint32_t LengthErr : 1; /*!< Frame size not matching with length field */
|
||||
uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */
|
||||
uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */
|
||||
uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */
|
||||
uint32_t FrameLength : 14; /*!< Byte length of received frame */
|
||||
uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */
|
||||
uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */
|
||||
};
|
||||
uint32_t Value;
|
||||
} RDES0;
|
||||
union {
|
||||
struct {
|
||||
uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */
|
||||
uint32_t Reserved1 : 1; /*!< Reserved */
|
||||
uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */
|
||||
uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */
|
||||
uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */
|
||||
uint32_t Reserved : 2; /*!< Reserved */
|
||||
uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */
|
||||
};
|
||||
uint32_t Value;
|
||||
} RDES1;
|
||||
uint32_t Buffer1Addr; /*!< Buffer1 address pointer */
|
||||
uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */
|
||||
volatile union {
|
||||
struct {
|
||||
uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */
|
||||
uint32_t IPHeadErr : 1; /*!< IP header error */
|
||||
uint32_t IPPayloadErr : 1; /*!< IP payload error */
|
||||
uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */
|
||||
uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */
|
||||
uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */
|
||||
uint32_t MessageType : 4; /*!< PTP Message Type */
|
||||
uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */
|
||||
uint32_t PTPVersion : 1; /*!< Version of PTP protocol */
|
||||
uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */
|
||||
uint32_t Reserved1 : 1; /*!< Reserved */
|
||||
uint32_t AVPacketReceived : 1; /*!< AV packet is received */
|
||||
uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */
|
||||
uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */
|
||||
uint32_t Reserved2 : 3; /*!< Reserved */
|
||||
uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */
|
||||
uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */
|
||||
uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */
|
||||
uint32_t Reserved3 : 4; /*!< Reserved */
|
||||
};
|
||||
uint32_t Value;
|
||||
} ExtendedStatus;
|
||||
uint32_t Reserved; /*!< Reserved */
|
||||
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
|
||||
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
|
||||
} eth_dma_rx_descriptor_t;
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
|
||||
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
|
||||
|
||||
#define EMAC_DMADESC_OWNER_CPU (0)
|
||||
#define EMAC_DMADESC_OWNER_DMA (1)
|
||||
|
||||
_Static_assert(sizeof(eth_dma_rx_descriptor_t) == 32, "eth_dma_rx_descriptor_t should occupy 32 bytes in memory");
|
||||
|
||||
typedef struct {
|
||||
emac_mac_dev_t *mac_regs;
|
||||
emac_dma_dev_t *dma_regs;
|
||||
emac_ext_dev_t *ext_regs;
|
||||
uint8_t **rx_buf;
|
||||
uint8_t **tx_buf;
|
||||
void *descriptors;
|
||||
eth_dma_rx_descriptor_t *rx_desc;
|
||||
eth_dma_tx_descriptor_t *tx_desc;
|
||||
} emac_hal_context_t;
|
||||
|
||||
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
|
||||
uint8_t **rx_buf, uint8_t **tx_buf);
|
||||
|
||||
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_lowlevel_init(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_reset(emac_hal_context_t *hal);
|
||||
|
||||
bool emac_hal_is_reset_done(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_init_mac_default(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_init_dma_default(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed);
|
||||
|
||||
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex);
|
||||
|
||||
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable);
|
||||
|
||||
/**
|
||||
* @brief Send MAC-CTRL frames to peer (EtherType=0x8808, opcode=0x0001, dest_addr=MAC-specific-ctrl-proto-01 (01:80:c2:00:00:01))
|
||||
*/
|
||||
void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable);
|
||||
|
||||
bool emac_hal_is_mii_busy(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write);
|
||||
|
||||
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value);
|
||||
|
||||
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr);
|
||||
|
||||
void emac_hal_start(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_stop(emac_hal_context_t *hal);
|
||||
|
||||
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
|
||||
|
||||
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
|
||||
|
||||
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc);
|
||||
|
||||
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable);
|
||||
|
||||
void emac_hal_isr(void *arg);
|
||||
|
||||
void emac_hal_tx_complete_cb(void *arg);
|
||||
|
||||
void emac_hal_tx_unavail_cb (void *arg);
|
||||
|
||||
void emac_hal_rx_complete_cb (void *arg);
|
||||
|
||||
void emac_hal_rx_early_cb(void *arg);
|
||||
|
||||
void emac_hal_rx_unavail_cb(void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
411
components/hal/esp32/include/hal/gpio_ll.h
Normal file
411
components/hal/esp32/include/hal/gpio_ll.h
Normal file
@@ -0,0 +1,411 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 GPIO register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "hal/gpio_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Get GPIO hardware instance with giving gpio num
|
||||
#define GPIO_LL_GET_HW(num) (((num) == 0) ? (&GPIO) : NULL)
|
||||
|
||||
/**
|
||||
* @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 = (core_id == 0) ? hw->pcpu_int : hw->acpu_int;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get GPIO interrupt status high
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param core_id interrupt core id
|
||||
* @param status interrupt status high
|
||||
*/
|
||||
static inline void gpio_ll_get_intr_status_high(gpio_dev_t *hw, uint32_t core_id, uint32_t *status)
|
||||
{
|
||||
*status = (core_id == 0) ? hw->pcpu_int1.intr : hw->acpu_int1.intr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear GPIO interrupt status
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param mask interrupt status clear mask
|
||||
*/
|
||||
static inline void gpio_ll_clear_intr_status(gpio_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->status_w1tc = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear GPIO interrupt status high
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param mask interrupt status high clear mask
|
||||
*/
|
||||
static inline void gpio_ll_clear_intr_status_high(gpio_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->status1_w1tc.intr_st = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable GPIO module interrupt signal
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param core_id Interrupt enabled CPU to corresponding ID
|
||||
* @param gpio_num GPIO number. If you want to enable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
*/
|
||||
static inline void gpio_ll_intr_enable_on_core(gpio_dev_t *hw, uint32_t core_id, gpio_num_t gpio_num)
|
||||
{
|
||||
if (core_id == 0) {
|
||||
hw->pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA; //enable pro cpu intr
|
||||
} else {
|
||||
hw->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)
|
||||
{
|
||||
if (gpio_num < 32) {
|
||||
hw->enable_w1tc = (0x1 << gpio_num);
|
||||
} else {
|
||||
hw->enable1_w1tc.data = (0x1 << (gpio_num - 32));
|
||||
}
|
||||
|
||||
// Ensure no other output signal is routed via GPIO matrix to this pin
|
||||
REG_WRITE(GPIO_FUNC0_OUT_SEL_CFG_REG + (gpio_num * 4),
|
||||
SIG_GPIO_OUT_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable output mode on GPIO.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number
|
||||
*/
|
||||
static inline void gpio_ll_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
if (gpio_num < 32) {
|
||||
hw->enable_w1ts = (0x1 << gpio_num);
|
||||
} else {
|
||||
hw->enable1_w1ts.data = (0x1 << (gpio_num - 32));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable open-drain mode on GPIO.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number
|
||||
*/
|
||||
static inline void gpio_ll_od_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
hw->pin[gpio_num].pad_driver = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable open-drain mode on GPIO.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number
|
||||
*/
|
||||
static inline void gpio_ll_od_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
hw->pin[gpio_num].pad_driver = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO set output level
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
* @param level Output level. 0: low ; 1: high
|
||||
*/
|
||||
static inline void gpio_ll_set_level(gpio_dev_t *hw, gpio_num_t gpio_num, uint32_t level)
|
||||
{
|
||||
if (level) {
|
||||
if (gpio_num < 32) {
|
||||
hw->out_w1ts = (1 << gpio_num);
|
||||
} else {
|
||||
hw->out1_w1ts.data = (1 << (gpio_num - 32));
|
||||
}
|
||||
} else {
|
||||
if (gpio_num < 32) {
|
||||
hw->out_w1tc = (1 << gpio_num);
|
||||
} else {
|
||||
hw->out1_w1tc.data = (1 << (gpio_num - 32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GPIO get input level
|
||||
*
|
||||
* @warning If the pad is not configured for input (or input and output) the returned value is always 0.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
|
||||
*
|
||||
* @return
|
||||
* - 0 the GPIO input level is 0
|
||||
* - 1 the GPIO input level is 1
|
||||
*/
|
||||
static inline int gpio_ll_get_level(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
if (gpio_num < 32) {
|
||||
return (hw->in >> gpio_num) & 0x1;
|
||||
} else {
|
||||
return (hw->in1.data >> (gpio_num - 32)) & 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable GPIO wake-up function.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number.
|
||||
* @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
|
||||
*/
|
||||
static inline void gpio_ll_wakeup_enable(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
|
||||
{
|
||||
hw->pin[gpio_num].int_type = intr_type;
|
||||
hw->pin[gpio_num].wakeup_enable = 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable GPIO wake-up function.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number
|
||||
*/
|
||||
static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
hw->pin[gpio_num].wakeup_enable = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set GPIO pad drive capability
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number, only support output GPIOs
|
||||
* @param strength Drive capability of the pad
|
||||
*/
|
||||
static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t strength)
|
||||
{
|
||||
SET_PERI_REG_BITS(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, strength, FUN_DRV_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get GPIO pad drive capability
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number, only support output GPIOs
|
||||
* @param strength Pointer to accept drive capability of the pad
|
||||
*/
|
||||
static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_drive_cap_t *strength)
|
||||
{
|
||||
*strength = GET_PERI_REG_BITS2(GPIO_PIN_MUX_REG[gpio_num], FUN_DRV_V, FUN_DRV_S);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable all digital gpio pad hold function during Deep-sleep.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
*/
|
||||
static inline void gpio_ll_deep_sleep_hold_en(gpio_dev_t *hw)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable all digital gpio pad hold function during Deep-sleep.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
*/
|
||||
static inline void gpio_ll_deep_sleep_hold_dis(gpio_dev_t *hw)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_AUTOHOLD_EN_M);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable gpio pad hold function.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number, only support output GPIOs
|
||||
*/
|
||||
static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable gpio pad hold function.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number, only support output GPIOs
|
||||
*/
|
||||
static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set pad input to a peripheral signal through the IOMUX.
|
||||
*
|
||||
* @param hw Peripheral GPIO hardware instance address.
|
||||
* @param gpio_num GPIO number of the pad.
|
||||
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
|
||||
*/
|
||||
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
|
||||
{
|
||||
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 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);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
860
components/hal/esp32/include/hal/i2c_ll.h
Normal file
860
components/hal/esp32/include/hal/i2c_ll.h
Normal file
@@ -0,0 +1,860 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for I2C register operations
|
||||
|
||||
#pragma once
|
||||
#include "soc/i2c_periph.h"
|
||||
#include "hal/i2c_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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 scl_low; /*!< I2C scl low period */
|
||||
uint16_t scl_high; /*!< I2C scl hight period */
|
||||
uint16_t sda_hold; /*!< I2C scl low period */
|
||||
uint16_t sda_sample; /*!< I2C sda sample time */
|
||||
uint16_t setup; /*!< I2C start and stop condition setup period */
|
||||
uint16_t hold; /*!< I2C start and stop condition hold period */
|
||||
uint16_t tout; /*!< I2C bus timeout period */
|
||||
} i2c_clk_cal_t;
|
||||
|
||||
// Get the I2C hardware instance
|
||||
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
|
||||
// Get the I2C hardware FIFO address
|
||||
#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num))
|
||||
// I2C master TX interrupt bitmap
|
||||
#define I2C_LL_MASTER_TX_INT (I2C_ACK_ERR_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
// I2C master RX interrupt bitmap
|
||||
#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
|
||||
// I2C slave TX interrupt bitmap
|
||||
#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_EMPTY_INT_ENA_M)
|
||||
// I2C slave RX interrupt bitmap
|
||||
#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M)
|
||||
//I2C base clock freq 80M
|
||||
#define I2C_BASE_CLK_FREQ (80000000)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Calculate I2C bus frequency
|
||||
*
|
||||
* @param source_clk I2C source clock
|
||||
* @param bus_freq I2C bus frequency
|
||||
* @param clk_cal Pointer to accept the clock configuration
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal)
|
||||
{
|
||||
uint32_t half_cycle = source_clk / bus_freq / 2;
|
||||
clk_cal->scl_low = half_cycle;
|
||||
clk_cal->scl_high = half_cycle;
|
||||
clk_cal->sda_hold = half_cycle / 2;
|
||||
clk_cal->sda_sample = clk_cal->scl_high / 2;
|
||||
clk_cal->setup = half_cycle;
|
||||
clk_cal->hold = half_cycle;
|
||||
clk_cal->tout = half_cycle * 20; //default we set the timeout value to 10 bus cycles.
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure the I2C bus timing related register.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param bus_cfg Pointer to the data structure holding the register configuration.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_bus_timing(i2c_dev_t *hw, i2c_clk_cal_t *bus_cfg)
|
||||
{
|
||||
//scl period
|
||||
hw->scl_low_period.period = bus_cfg->scl_low;
|
||||
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;
|
||||
hw->scl_stop_hold.time = bus_cfg->hold;
|
||||
hw->timeout.tout = bus_cfg->tout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset I2C txFIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_txfifo_rst(i2c_dev_t *hw)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_rst = 1;
|
||||
hw->fifo_conf.tx_fifo_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset I2C rxFIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_rxfifo_rst(i2c_dev_t *hw)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_rst = 1;
|
||||
hw->fifo_conf.rx_fifo_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C SCL timing
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param hight_period The I2C SCL hight period (in APB cycle)
|
||||
* @param low_period The I2C SCL low period (in APB cycle)
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int low_period)
|
||||
{
|
||||
hw->scl_low_period.period = low_period;
|
||||
hw->scl_high_period.period = hight_period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C interrupt status
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param mask Interrupt mask needs to be cleared
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->int_clr.val = mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2C interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param mask Interrupt mask needs to be enabled
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->int_ena.val |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable I2C interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param mask Interrupt mask needs to be disabled
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask)
|
||||
{
|
||||
hw->int_ena.val &= (~mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C interrupt status
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return I2C interrupt status
|
||||
*/
|
||||
static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->int_status.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C memory access mode, FIFO mode or non-FIFO mode
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param fifo_mode_en Set true to enable FIFO access mode, else, set it false
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en)
|
||||
{
|
||||
hw->fifo_conf.nonfifo_en = fifo_mode_en ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C timeout
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param tout_num The I2C timeout value needs to be set (in APB cycle)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout)
|
||||
{
|
||||
hw->timeout.tout = tout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C slave address
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param slave_addr I2C slave address needs to be set
|
||||
* @param addr_10bit_en Set true to enable 10-bit slave address mode, set false to enable 7-bit address mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_slave_addr(i2c_dev_t *hw, uint16_t slave_addr, bool addr_10bit_en)
|
||||
{
|
||||
hw->slave_addr.addr = slave_addr;
|
||||
hw->slave_addr.en_10bit = addr_10bit_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write I2C hardware command register
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param cmd I2C hardware command
|
||||
* @param cmd_idx The index of the command register, should be less than 16
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_write_cmd_reg(i2c_dev_t *hw, i2c_hw_cmd_t cmd, int cmd_idx)
|
||||
{
|
||||
hw->command[cmd_idx].val = cmd.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C start timing
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param start_setup The start condition setup period (in APB cycle)
|
||||
* @param start_hold The start condition hold period (in APB cycle)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_start_timing(i2c_dev_t *hw, int start_setup, int start_hold)
|
||||
{
|
||||
hw->scl_rstart_setup.time = start_setup;
|
||||
hw->scl_start_hold.time = start_hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C stop timing
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param stop_setup The stop condition setup period (in APB cycle)
|
||||
* @param stop_hold The stop condition hold period (in APB cycle)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_stop_timing(i2c_dev_t *hw, int stop_setup, int stop_hold)
|
||||
{
|
||||
hw->scl_stop_setup.time = stop_setup;
|
||||
hw->scl_stop_hold.time = stop_hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C stop timing
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param sda_sample The SDA sample time (in APB cycle)
|
||||
* @param sda_hold The SDA hold time (in APB cycle)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_sda_timing(i2c_dev_t *hw, int sda_sample, int sda_hold)
|
||||
{
|
||||
hw->sda_hold.time = sda_hold;
|
||||
hw->sda_sample.time = sda_sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2C txFIFO empty threshold
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param empty_thr The txFIFO empty threshold
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_txfifo_empty_thr(i2c_dev_t *hw, uint8_t empty_thr)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_empty_thrhd = empty_thr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2C rxFIFO full threshold
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param full_thr The rxFIFO full threshold
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_full_thrhd = full_thr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the I2C data mode, LSB or MSB
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param tx_mode Tx data bit mode
|
||||
* @param rx_mode Rx data bit mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_data_mode(i2c_dev_t *hw, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode)
|
||||
{
|
||||
hw->ctr.tx_lsb_first = tx_mode;
|
||||
hw->ctr.rx_lsb_first = rx_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the I2C data mode
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param tx_mode Pointer to accept the received bytes mode
|
||||
* @param rx_mode Pointer to accept the sended bytes mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_get_data_mode(i2c_dev_t *hw, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode)
|
||||
{
|
||||
*tx_mode = hw->ctr.tx_lsb_first;
|
||||
*rx_mode = hw->ctr.rx_lsb_first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C sda timing configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param sda_sample Pointer to accept the SDA sample timing configuration
|
||||
* @param sda_hold Pointer to accept the SDA hold timing configuration
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sda_hold)
|
||||
{
|
||||
*sda_hold = hw->sda_hold.time;
|
||||
*sda_sample = hw->sda_sample.time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the I2C hardware version
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return The I2C hardware version
|
||||
*/
|
||||
static inline uint32_t i2c_ll_get_hw_version(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the I2C bus is busy
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return True if I2C state machine is busy, else false will be returned
|
||||
*/
|
||||
static inline bool i2c_ll_is_bus_busy(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->status_reg.bus_busy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if I2C is master mode
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return True if I2C is master mode, else false will be returned
|
||||
*/
|
||||
static inline bool i2c_ll_is_master_mode(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->ctr.ms_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the rxFIFO readable length
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return RxFIFO readable length
|
||||
*/
|
||||
static inline uint32_t i2c_ll_get_rxfifo_cnt(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->status_reg.rx_fifo_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C txFIFO writable length
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return TxFIFO writable length
|
||||
*/
|
||||
static inline uint32_t i2c_ll_get_txfifo_len(i2c_dev_t *hw)
|
||||
{
|
||||
return SOC_I2C_FIFO_LEN - hw->status_reg.tx_fifo_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C timeout configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return The I2C timeout value
|
||||
*/
|
||||
static inline uint32_t i2c_ll_get_tout(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->timeout.tout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start I2C transfer
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_trans_start(i2c_dev_t *hw)
|
||||
{
|
||||
hw->ctr.trans_start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C start timing configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param setup_time Pointer to accept the start condition setup period
|
||||
* @param hold_time Pointer to accept the start condition hold period
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_get_start_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
|
||||
{
|
||||
*setup_time = hw->scl_rstart_setup.time;
|
||||
*hold_time = hw->scl_start_hold.time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C stop timing configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param setup_time Pointer to accept the stop condition setup period
|
||||
* @param hold_time Pointer to accept the stop condition hold period
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
|
||||
{
|
||||
*setup_time = hw->scl_stop_setup.time;
|
||||
*hold_time = hw->scl_stop_hold.time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C SCL timing configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param high_period Pointer to accept the SCL high period
|
||||
* @param low_period Pointer to accept the SCL low period
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *low_period)
|
||||
{
|
||||
*high_period = hw->scl_high_period.period;
|
||||
*low_period = hw->scl_low_period.period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the I2C hardware txFIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param ptr Pointer to data buffer
|
||||
* @param len Amount of data needs to be writen
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c;
|
||||
for(int i = 0; i < len; i++) {
|
||||
WRITE_PERI_REG(fifo_addr, ptr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the I2C hardware rxFIFO
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param ptr Pointer to data buffer
|
||||
* @param len Amount of data needs read
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_read_rxfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
for(int i = 0; i < len; i++) {
|
||||
ptr[i] = hw->fifo_data.data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2C hardware filter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param filter_num If the glitch period on the line is less than this value, it can be filtered out
|
||||
* If `filter_num == 0`, the filter will be disabled
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_filter(i2c_dev_t *hw, uint8_t filter_num)
|
||||
{
|
||||
if(filter_num > 0) {
|
||||
hw->scl_filter_cfg.thres = filter_num;
|
||||
hw->sda_filter_cfg.thres = filter_num;
|
||||
hw->scl_filter_cfg.en = 1;
|
||||
hw->sda_filter_cfg.en = 1;
|
||||
} else {
|
||||
hw->scl_filter_cfg.en = 0;
|
||||
hw->sda_filter_cfg.en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C hardware filter configuration
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return The hardware filter configuration
|
||||
*/
|
||||
static inline uint8_t i2c_ll_get_filter(i2c_dev_t *hw)
|
||||
{
|
||||
return hw->sda_filter_cfg.thres;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2C master TX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_enable_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = ~0;
|
||||
hw->int_ena.val = I2C_LL_MASTER_TX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2C master RX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_enable_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = ~0;
|
||||
hw->int_ena.val = I2C_LL_MASTER_RX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable I2C master TX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_disable_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val &= (~I2C_LL_MASTER_TX_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable I2C master RX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_disable_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val &= (~I2C_LL_MASTER_RX_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C master TX interrupt status register
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_clr_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = I2C_LL_MASTER_TX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C master RX interrupt status register
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_clr_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = I2C_LL_MASTER_RX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_enable_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val |= I2C_LL_SLAVE_TX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2C slave RX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_enable_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val |= I2C_LL_SLAVE_RX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable I2C slave TX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_disable_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val &= (~I2C_LL_SLAVE_TX_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable I2C slave RX interrupt
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_disable_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.val &= (~I2C_LL_SLAVE_RX_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C slave TX interrupt status register
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_clr_tx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = I2C_LL_SLAVE_TX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C slave RX interrupt status register.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_clr_rx_it(i2c_dev_t *hw)
|
||||
{
|
||||
hw->int_clr.val = I2C_LL_SLAVE_RX_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reste I2C master FSM. When the master FSM is stuck, call this function to reset the FSM
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_fsm_rst(i2c_dev_t *hw)
|
||||
{
|
||||
;//ESP32 do not support
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling the bus low,
|
||||
* master can controls the SCL bus to generate 9 CLKs.
|
||||
*
|
||||
* Note: The master cannot detect if deadlock happens, but when the scl_st_to interrupt is generated, a deadlock may occur.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw)
|
||||
{
|
||||
;//ESP32 do not support
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2C source clock
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param src_clk Source clock of the I2C
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_sclk_t src_clk)
|
||||
{
|
||||
;//Not support on ESP32
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C master interrupt event
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param event Pointer to accept the interrupt event
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
|
||||
{
|
||||
typeof(hw->int_status) int_sts = hw->int_status;
|
||||
if (int_sts.arbitration_lost) {
|
||||
*event = I2C_INTR_EVENT_ARBIT_LOST;
|
||||
} else if (int_sts.ack_err) {
|
||||
*event = I2C_INTR_EVENT_NACK;
|
||||
} else if (int_sts.time_out) {
|
||||
*event = I2C_INTR_EVENT_TOUT;
|
||||
} else if (int_sts.end_detect) {
|
||||
*event = I2C_INTR_EVENT_END_DET;
|
||||
} else if (int_sts.trans_complete) {
|
||||
*event = I2C_INTR_EVENT_TRANS_DONE;
|
||||
} else {
|
||||
*event = I2C_INTR_EVENT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get I2C slave interrupt event
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param event Pointer to accept the interrupt event
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
|
||||
{
|
||||
typeof(hw->int_status) int_sts = hw->int_status;
|
||||
if (int_sts.tx_fifo_empty) {
|
||||
*event = I2C_INTR_EVENT_TXFIFO_EMPTY;
|
||||
} else if (int_sts.trans_complete) {
|
||||
*event = I2C_INTR_EVENT_TRANS_DONE;
|
||||
} else if (int_sts.rx_fifo_full) {
|
||||
*event = I2C_INTR_EVENT_RXFIFO_FULL;
|
||||
} else {
|
||||
*event = I2C_INTR_EVENT_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init I2C master
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_master_init(i2c_dev_t *hw)
|
||||
{
|
||||
typeof(hw->ctr) ctrl_reg;
|
||||
ctrl_reg.val = 0;
|
||||
ctrl_reg.ms_mode = 1;
|
||||
ctrl_reg.sda_force_out = 1;
|
||||
ctrl_reg.scl_force_out = 1;
|
||||
hw->ctr.val = ctrl_reg.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Init I2C slave
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void i2c_ll_slave_init(i2c_dev_t *hw)
|
||||
{
|
||||
typeof(hw->ctr) ctrl_reg;
|
||||
ctrl_reg.val = 0;
|
||||
ctrl_reg.sda_force_out = 1;
|
||||
ctrl_reg.scl_force_out = 1;
|
||||
hw->ctr.val = ctrl_reg.val;
|
||||
hw->fifo_conf.fifo_addr_cfg_en = 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
924
components/hal/esp32/include/hal/i2s_ll.h
Normal file
924
components/hal/esp32/include/hal/i2s_ll.h
Normal file
@@ -0,0 +1,924 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 I2S register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_periph.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) : (((num) == 1) ? (&I2S1) : 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)
|
||||
{
|
||||
hw->conf.rx_fifo_reset = 1;
|
||||
hw->conf.rx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset tx fifo
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_fifo_reset = 1;
|
||||
hw->conf.tx_fifo_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable rx interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 1;
|
||||
hw->int_ena.in_dscr_err = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable rx interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.in_suc_eof = 0;
|
||||
hw->int_ena.in_dscr_err = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable tx interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 0;
|
||||
hw->int_ena.out_dscr_err = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable tx interrupt
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw)
|
||||
{
|
||||
hw->int_ena.out_eof = 1;
|
||||
hw->int_ena.out_dscr_err = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset dma in
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw)
|
||||
{
|
||||
hw->lc_conf.in_rst = 1;
|
||||
hw->lc_conf.in_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset dma out
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw)
|
||||
{
|
||||
hw->lc_conf.out_rst = 1;
|
||||
hw->lc_conf.out_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset tx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_reset_tx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_reset = 1;
|
||||
hw->conf.tx_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset rx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_reset_rx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_reset = 1;
|
||||
hw->conf.rx_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start out link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_start_out_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->out_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start tx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_start_tx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start in link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_start_in_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->in_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start rx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_start_rx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop out link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_stop_out_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->out_link.stop = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop tx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_stop_tx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.tx_start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop in link
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_stop_in_link(i2s_dev_t *hw)
|
||||
{
|
||||
hw->in_link.stop = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop rx
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_stop_rx(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable dma
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_enable_dma(i2s_dev_t *hw)
|
||||
{
|
||||
//Enable and configure DMA
|
||||
typeof(hw->lc_conf) lc_conf;
|
||||
lc_conf.val = 0;
|
||||
lc_conf.out_eof_mode = 1;
|
||||
hw->lc_conf.val = lc_conf.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->int_clr.val = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf_chan.tx_chan_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S rx chan mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set rx chan mode
|
||||
*/
|
||||
static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->conf_chan.rx_chan_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S out link address
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param val value to set out link address
|
||||
*/
|
||||
static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val)
|
||||
{
|
||||
hw->out_link.addr = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 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)
|
||||
{
|
||||
hw->in_link.addr = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
// On ESP32, the eof_num count in words.
|
||||
hw->rx_eof_num = val / 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->pdm_freq_conf.tx_pdm_fp = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_freq_conf.tx_pdm_fs = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->clkm_conf.clkm_div_num = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->clkm_conf.clkm_div_b = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->clkm_conf.clkm_div_a = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->sample_rate_conf.tx_bck_div_num = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->sample_rate_conf.rx_bck_div_num = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->clkm_conf.clka_en = (val == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->sample_rate_conf.tx_bits_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->sample_rate_conf.rx_bits_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.rx_sinc_dsr_16_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->fifo_conf.dscr_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf2.lcd_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf2.camera_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.pcm2pdm_conv_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.pdm2pcm_conv_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.rx_pdm_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.tx_pdm_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->fifo_conf.tx_fifo_mod_force_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->fifo_conf.rx_fifo_mod_force_en = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_right_first = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_right_first = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_slave_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_slave_mod = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
*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)
|
||||
{
|
||||
hw->conf.tx_msb_right = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_msb_right = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_mono = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_mono = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->pdm_conf.tx_sinc_osr2 = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.sig_loopback = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set I2S RX to MSB Alignment Standard
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_short_sync = 1;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_short_sync = 1;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.tx_short_sync = 0;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
hw->conf.rx_short_sync = 0;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S TX pdm
|
||||
*
|
||||
* @param sample_rate The sample rate to be set.
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate)
|
||||
{
|
||||
uint32_t fp = 96;
|
||||
uint32_t fs = sample_rate / 1000 * 10;
|
||||
hw->pdm_freq_conf.tx_pdm_fp = fp;
|
||||
hw->pdm_freq_conf.tx_pdm_fs = fs;
|
||||
hw->pdm_conf.tx_sinc_osr2 = fp/fs;
|
||||
hw->pdm_conf.pcm2pdm_conv_en = 1;
|
||||
hw->pdm_conf.tx_pdm_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure I2S TX pdm
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_rx_pdm_cfg(i2s_dev_t *hw)
|
||||
{
|
||||
hw->pdm_conf.rx_sinc_dsr_16_en = 0;
|
||||
hw->pdm_conf.pdm2pcm_conv_en = 1;
|
||||
hw->pdm_conf.rx_pdm_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S build in ADC mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_build_in_adc_ena(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf2.lcd_en = 1;
|
||||
hw->conf2.camera_en = 0;
|
||||
hw->conf.rx_msb_shift = 0;
|
||||
hw->conf.rx_short_sync = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable I2S build in DAC mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
static inline void i2s_ll_build_in_dac_ena(i2s_dev_t *hw)
|
||||
{
|
||||
hw->conf2.lcd_en = 1;
|
||||
hw->conf2.camera_en = 0;
|
||||
hw->conf.tx_right_first = 1;
|
||||
hw->conf.tx_msb_shift = 0;
|
||||
hw->conf.tx_short_sync = 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
466
components/hal/esp32/include/hal/ledc_ll.h
Normal file
466
components/hal/esp32/include/hal/ledc_ll.h
Normal file
@@ -0,0 +1,466 @@
|
||||
// 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.
|
||||
|
||||
// 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"
|
||||
|
||||
#define LEDC_LL_GET_HW() &LEDC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set LEDC low speed timer clock
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param slow_clk_sel LEDC low speed timer clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t slow_clk_sel){
|
||||
hw->conf.slow_clk_sel = slow_clk_sel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC low speed timer clock
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param slow_clk_sel LEDC low speed timer clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t *slow_clk_sel){
|
||||
*slow_clk_sel = hw->conf.slow_clk_sel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update LEDC low speed timer
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_ls_timer_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset LEDC timer
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_timer_rst(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pause LEDC timer
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_timer_pause(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume LEDC timer
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_timer_resume(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC timer clock divider
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider = clock_divider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC timer clock divider
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *clock_divider){
|
||||
*clock_divider = hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC timer clock source
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param clk_src Timer clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t clk_src){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = (clk_src == LEDC_APB_CLK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC timer clock source
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param clk_src Pointer to accept the timer clock source
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t *clk_src){
|
||||
if (hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel) {
|
||||
*clk_src = LEDC_APB_CLK;
|
||||
} else {
|
||||
*clk_src = LEDC_REF_TICK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC duty resolution
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t duty_resolution){
|
||||
hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution = duty_resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC duty resolution
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *duty_resolution){
|
||||
*duty_resolution = hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update channel configure when select low speed mode
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC max duty
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param max_duty Pointer to accept the max duty
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *max_duty){
|
||||
int timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
|
||||
*max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC hpoint value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val){
|
||||
hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC hpoint value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *hpoint_val){
|
||||
*hpoint_val = hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC the integer part of duty value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_val){
|
||||
hw->channel_group[speed_mode].channel[channel_num].duty.duty = duty_val << 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC duty value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_val Pointer to accept the LEDC duty value
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *duty_val){
|
||||
*duty_val = (hw->channel_group[speed_mode].channel[channel_num].duty_rd.duty_read >> 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set LEDC duty change direction
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_direction LEDC duty change direction, increase or decrease
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc = duty_direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LEDC duty change direction
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_direction Pointer to accept the LEDC duty change direction, increase or decrease
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t *duty_direction){
|
||||
*duty_direction = hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the number of increased or decreased times
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_num The number of increased or decreased times
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_num(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_num){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_num = duty_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the duty cycles of increase or decrease
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_cycle The duty cycles
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_cycle(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_cycle){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_cycle = duty_cycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the step scale of increase or decrease
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_scale The step scale
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_scale(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_scale){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_scale = duty_scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the output enable
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param sig_out_en The output enable status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_sig_out_en(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool sig_out_en){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf0.sig_out_en = sig_out_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the duty start
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param duty_start The duty start
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool duty_start){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = duty_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set output idle level
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param idle_level The output idle level
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t idle_level){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf0.idle_lv = idle_level & 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set fade end interrupt enable
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param fade_end_intr_en The fade end interrupt enable status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool fade_end_intr_en){
|
||||
uint32_t value = hw->int_ena.val;
|
||||
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
|
||||
hw->int_ena.val = fade_end_intr_en ? (value | BIT(int_en_base + channel_num)) : (value & (~(BIT(int_en_base + channel_num))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get fade end interrupt status
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param intr_status The fade end interrupt status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, uint32_t *intr_status){
|
||||
uint32_t value = hw->int_st.val;
|
||||
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
|
||||
*intr_status = (value >> int_en_base) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear fade end interrupt status
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_clear_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
|
||||
uint32_t int_en_base = (speed_mode == LEDC_LOW_SPEED_MODE) ? LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S;
|
||||
hw->int_clr.val = BIT(int_en_base + channel_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set timer index of the specified channel
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_bind_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t timer_sel){
|
||||
hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel = timer_sel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get timer index of the specified channel
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers
|
||||
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
|
||||
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
|
||||
* @param timer_sel Pointer to accept the LEDC timer index
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t *timer_sel){
|
||||
*timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
735
components/hal/esp32/include/hal/mcpwm_ll.h
Normal file
735
components/hal/esp32/include/hal/mcpwm_ll.h
Normal file
@@ -0,0 +1,735 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 MCPWM register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <soc/mcpwm_periph.h>
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "hal/mcpwm_types.h"
|
||||
#include "soc/mcpwm_caps.h"
|
||||
#include "hal/hal_defs.h"
|
||||
|
||||
#include "esp_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Get the address of peripheral registers
|
||||
#define MCPWM_LL_GET_HW(ID) (((ID)==0)? &MCPWM0: &MCPWM1)
|
||||
|
||||
|
||||
/********************* Global *******************/
|
||||
/**
|
||||
* Initialize common registers.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
*/
|
||||
static inline void mcpwm_ll_init(mcpwm_dev_t *mcpwm)
|
||||
{
|
||||
mcpwm->update_cfg.global_up_en = 1;
|
||||
mcpwm->update_cfg.global_force_up = 1;
|
||||
mcpwm->update_cfg.global_force_up = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prescale of the PWM main clock to the input clock.
|
||||
*
|
||||
* Input clock is 160MHz, PWM main clock cycle = 6.25ns*(prescale + 1).
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param prescale Prescale factor, 0-255.
|
||||
*/
|
||||
static inline void mcpwm_ll_set_clock_prescale(mcpwm_dev_t *mcpwm, int prescale)
|
||||
{
|
||||
mcpwm->clk_cfg.prescale = prescale;
|
||||
}
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP0, MCPWM_CAP0_INT_RAW);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP1, MCPWM_CAP1_INT_RAW);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_LL_INTR_CAP2, MCPWM_CAP2_INT_RAW);
|
||||
|
||||
/**
|
||||
* Get raw interrupt status.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @return The triggered interrupts, ORed by active interrupts.
|
||||
*/
|
||||
static inline mcpwm_intr_t mcpwm_ll_get_intr(mcpwm_dev_t *mcpwm)
|
||||
{
|
||||
return mcpwm->int_raw.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the interrupts.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param intr Bitwise ORed interrupts to clear.
|
||||
*/
|
||||
static inline void mcpwm_ll_clear_intr(mcpwm_dev_t* mcpwm, mcpwm_intr_t intr)
|
||||
{
|
||||
mcpwm->int_clr.val = intr;
|
||||
}
|
||||
|
||||
/********************* Timer *******************/
|
||||
/**
|
||||
* Set the prescale of the Timer_x clock to the PWM main clock.
|
||||
*
|
||||
* Timer clock frequency = PWM main clock frequency/(prescale + 1).
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to set the prescale, 0-2.
|
||||
* @param prescale Prescale factor, 0-255.
|
||||
*/
|
||||
static inline void mcpwm_ll_timer_set_prescale(mcpwm_dev_t* mcpwm, int timer, uint32_t prescale)
|
||||
{
|
||||
mcpwm->timer[timer].period.prescale = prescale;
|
||||
}
|
||||
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_UP_COUNTER, 1);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_DOWN_COUNTER, 2);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_UP_DOWN_COUNTER, 3);
|
||||
|
||||
/**
|
||||
* Set the counting mode for the PWM timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to change counting mode, 0-2.
|
||||
* @param mode Counting mode to use.
|
||||
*/
|
||||
static inline void mcpwm_ll_timer_set_count_mode(mcpwm_dev_t *mcpwm, int timer, mcpwm_counter_type_t mode)
|
||||
{
|
||||
mcpwm->timer[timer].mode.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to start, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_timer_start(mcpwm_dev_t *mcpwm, int timer)
|
||||
{
|
||||
mcpwm->timer[timer].mode.start = 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to stop, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_timer_stop(mcpwm_dev_t *mcpwm, int timer)
|
||||
{
|
||||
mcpwm->timer[timer].mode.start = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the overflow period of a timer.
|
||||
*
|
||||
* The overflow rate will be Frequency of timer / period.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to set period, 0-2.
|
||||
* @param period Total timer count of each period, 0-65535.
|
||||
*/
|
||||
static inline void mcpwm_ll_timer_set_period(mcpwm_dev_t *mcpwm, int timer, uint32_t period)
|
||||
{
|
||||
|
||||
mcpwm->timer[timer].period.period = period - 1;
|
||||
mcpwm->timer[timer].period.upmethod = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the period setting of a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to get the period, 0-2.
|
||||
* @return Period setting value.
|
||||
*/
|
||||
static inline uint32_t mcpwm_ll_timer_get_period(mcpwm_dev_t *mcpwm, int timer)
|
||||
{
|
||||
return mcpwm->timer[timer].period.period + 1;
|
||||
}
|
||||
|
||||
/********************* Sync *******************/
|
||||
/**
|
||||
* Enable the synchronization feature for a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer Timer to set, 0-2.
|
||||
* @param enable true to enable, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_sync_enable(mcpwm_dev_t *mcpwm, int timer, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
mcpwm->timer[timer].sync.out_sel = 0;
|
||||
mcpwm->timer[timer].sync.in_en = 1;
|
||||
} else {
|
||||
mcpwm->timer[timer].sync.in_en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the phase (counter value) to reload when the sync signal triggers.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer Timer to set, 0-2.
|
||||
* @param reload_val The reloaded value.
|
||||
*/
|
||||
static inline void mcpwm_ll_sync_set_phase(mcpwm_dev_t *mcpwm, int timer, uint32_t reload_val)
|
||||
{
|
||||
mcpwm->timer[timer].sync.timer_phase = reload_val;
|
||||
}
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC0, 4);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC1, 5);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_SELECT_SYNC2, 6);
|
||||
/**
|
||||
* Set the sync signal source for a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param timer The timer to set, 0-2.
|
||||
* @param sync_sig The synchronization signal to use.
|
||||
*/
|
||||
static inline void mcpwm_ll_sync_set_input(mcpwm_dev_t *mcpwm, int timer, mcpwm_sync_signal_t sync_sig)
|
||||
{
|
||||
if (timer == 0) {
|
||||
mcpwm->timer_synci_cfg.t0_in_sel = sync_sig;
|
||||
} else if (timer == 1) {
|
||||
mcpwm->timer_synci_cfg.t1_in_sel = sync_sig;
|
||||
} else { //MCPWM_TIMER_2
|
||||
mcpwm->timer_synci_cfg.t2_in_sel = sync_sig;
|
||||
}
|
||||
}
|
||||
|
||||
/********************* Comparator *******************/
|
||||
/**
|
||||
* Select a timer for the specified operator to use.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to choose timer, 0-2.
|
||||
* @param timer The timer to use, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_operator_select_timer(mcpwm_dev_t *mcpwm, int op, int timer)
|
||||
{
|
||||
if (op == 0) {
|
||||
mcpwm->timer_sel.operator0_sel = timer;
|
||||
} else if (op == 1) {
|
||||
mcpwm->timer_sel.operator1_sel = timer;
|
||||
} else {
|
||||
mcpwm->timer_sel.operator2_sel = timer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the update method of the compare value of a timer
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op Operator to set, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_operator_set_compare_upmethod(mcpwm_dev_t *mcpwm, int op)
|
||||
{
|
||||
mcpwm->channel[op].cmpr_cfg.a_upmethod = BIT(0);
|
||||
mcpwm->channel[op].cmpr_cfg.b_upmethod = BIT(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one of the compare value of a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to get, 0-2.
|
||||
* @param cmp_n Comparer id to get, 0-1.
|
||||
* @return The set compare value.
|
||||
*/
|
||||
static inline uint32_t mcpwm_ll_operator_get_compare(mcpwm_dev_t *mcpwm, int op, int cmp_n)
|
||||
{
|
||||
return (mcpwm->channel[op].cmpr_value[cmp_n].cmpr_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one of the compare value of a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param cmp_n The comparer to set value, 0-1.
|
||||
* @param compare The compare value, 0-65535.
|
||||
*/
|
||||
static inline void mcpwm_ll_operator_set_compare(mcpwm_dev_t *mcpwm, int op, int cmp_n, uint32_t compare)
|
||||
{
|
||||
mcpwm->channel[op].cmpr_value[cmp_n].cmpr_val = compare;
|
||||
}
|
||||
|
||||
/********************* Generator *******************/
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_NO_CHANGE, 0);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_FORCE_LOW, 1);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_FORCE_HIGH, 2);
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_ACTION_TOGGLE, 3);
|
||||
/**
|
||||
* Set the action will be taken by a operator when its timer counts to zero.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set action, 0-2.
|
||||
* @param gen One generator of the operator to take the action, 0-1.
|
||||
* @param action Action to take.
|
||||
*/
|
||||
static inline void mcpwm_ll_gen_set_zero_action(mcpwm_dev_t *mcpwm, int op, int gen, mcpwm_output_action_t action)
|
||||
{
|
||||
mcpwm->channel[op].generator[gen].utez = action;
|
||||
mcpwm->channel[op].generator[gen].dtez = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action will be taken by a operator when its timer counts to the period value.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set action, 0-2.
|
||||
* @param gen One generator of the operator to take the action, 0-1.
|
||||
* @param action Action to take.
|
||||
*/
|
||||
static inline void mcpwm_ll_gen_set_period_action(mcpwm_dev_t *mcpwm, int op, int gen, mcpwm_output_action_t action)
|
||||
{
|
||||
mcpwm->channel[op].generator[gen].utep = action;
|
||||
mcpwm->channel[op].generator[gen].dtep = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action will be taken by a operator when its timer counts to the compare value.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set action, 0-2.
|
||||
* @param gen One generator of the operator to take the action, 0-1.
|
||||
* @param cmp_n The comparer to use.
|
||||
* @param up_action The action to take when the counter is counting up.
|
||||
* @param down_action The action to take when the counter is counting down.
|
||||
*/
|
||||
static inline void mcpwm_ll_gen_set_cmp_action(mcpwm_dev_t *mcpwm, int op, int gen,
|
||||
int cmp_n, mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
|
||||
{
|
||||
if (cmp_n == 0) {
|
||||
mcpwm->channel[op].generator[gen].utea = up_action;
|
||||
mcpwm->channel[op].generator[gen].dtea = down_action;
|
||||
} else {
|
||||
mcpwm->channel[op].generator[gen].uteb = up_action;
|
||||
mcpwm->channel[op].generator[gen].dteb = down_action;
|
||||
}
|
||||
}
|
||||
|
||||
/********************* Fault *******************/
|
||||
/**
|
||||
* Enable the fault detection feature for an input signal.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param fault_sig One of the signals to select, 0-2.
|
||||
* @param level The active level of the fault-detection signal.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_enable(mcpwm_dev_t *mcpwm, int fault_sig, bool level)
|
||||
{
|
||||
if (fault_sig == 0) {
|
||||
mcpwm->fault_detect.f0_en = 1;
|
||||
mcpwm->fault_detect.f0_pole = level;
|
||||
} else if (fault_sig == 1) {
|
||||
mcpwm->fault_detect.f1_en = 1;
|
||||
mcpwm->fault_detect.f1_pole = level;
|
||||
} else { //MCPWM_SELECT_F2
|
||||
mcpwm->fault_detect.f2_en = 1;
|
||||
mcpwm->fault_detect.f2_pole = level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the fault detection of an input signal.
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param fault_sig The signal to disable, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_disable(mcpwm_dev_t *mcpwm, int fault_sig)
|
||||
{
|
||||
if (fault_sig == 0) {
|
||||
mcpwm->fault_detect.f0_en = 0;
|
||||
} else if (fault_sig == 1) {
|
||||
mcpwm->fault_detect.f1_en = 0;
|
||||
} else { //MCPWM_SELECT_F2
|
||||
mcpwm->fault_detect.f2_en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the oneshot fault status of an operator.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to clear, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_clear_ost(mcpwm_dev_t *mcpwm, int op)
|
||||
{
|
||||
mcpwm->channel[op].tz_cfg1.clr_ost = 1;
|
||||
mcpwm->channel[op].tz_cfg1.clr_ost = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the oneshot mode to handle the fault when it occurs
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to handle the fault signal, 0-2.
|
||||
* @param signal The fault signal to set, 0-2.
|
||||
* @param enable true to enable oneshot, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_oneshot_enable_signal(mcpwm_dev_t *mcpwm, int op, int signal, bool enable)
|
||||
{
|
||||
if (signal == 0) {
|
||||
mcpwm->channel[op].tz_cfg0.f0_ost = enable;
|
||||
} else if (signal == 1) {
|
||||
mcpwm->channel[op].tz_cfg0.f1_ost = enable;
|
||||
} else { //MCPWM_SELECT_F2
|
||||
mcpwm->channel[op].tz_cfg0.f2_ost = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the oneshot enabled status of the operator
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to check, 0-2.
|
||||
* @param signal The fault signal to get, 0-2.
|
||||
*/
|
||||
static inline bool mcpwm_ll_fault_oneshot_signal_enabled(mcpwm_dev_t *mcpwm, int op, int signal)
|
||||
{
|
||||
if (signal == 0) {
|
||||
return mcpwm->channel[op].tz_cfg0.f0_ost;
|
||||
} else if (signal == 1) {
|
||||
return mcpwm->channel[op].tz_cfg0.f1_ost;
|
||||
} else { //MCPWM_SELECT_F2
|
||||
return mcpwm->channel[op].tz_cfg0.f2_ost;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the CBC (cycle-by-cycle) mode to handle the fault when it occurs.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to handle the fault signal, 0-2.
|
||||
* @param signal The fault signal to set, 0-2.
|
||||
* @param enable true to enable cbc mode, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_cbc_enable_signal(mcpwm_dev_t *mcpwm, int op, int signal, bool enable)
|
||||
{
|
||||
if (signal == 0) {
|
||||
mcpwm->channel[op].tz_cfg0.f0_cbc = enable;
|
||||
} else if (signal == 1) {
|
||||
mcpwm->channel[op].tz_cfg0.f1_cbc = enable;
|
||||
} else { //MCPWM_SELECT_F2
|
||||
mcpwm->channel[op].tz_cfg0.f2_cbc = enable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action that will be taken when the fault is handled by oneshot.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to handle the fault signal, 0-2.
|
||||
* @param gen The generator to take the action, 0-1.
|
||||
* @param up_action Action to take when fault happens when counting up.
|
||||
* @param down_action Action to take when fault happens when counting down.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_set_oneshot_action(mcpwm_dev_t *mcpwm, int op, int gen,
|
||||
mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
|
||||
{
|
||||
if (gen == 0) {
|
||||
mcpwm->channel[op].tz_cfg0.a_ost_u = up_action;
|
||||
mcpwm->channel[op].tz_cfg0.a_ost_d = down_action;
|
||||
} else {
|
||||
mcpwm->channel[op].tz_cfg0.b_ost_u = up_action;
|
||||
mcpwm->channel[op].tz_cfg0.b_ost_d = down_action;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action that will be taken when the fault is handled cycle by cycle.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to handle the fault signal, 0-2.
|
||||
* @param gen The generator to take the action, 0-1.
|
||||
* @param up_action Action to take when fault happens when counting up.
|
||||
* @param down_action Action to take when fault happens when counting down.
|
||||
*/
|
||||
static inline void mcpwm_ll_fault_set_cyc_action(mcpwm_dev_t *mcpwm, int op, int gen,
|
||||
mcpwm_output_action_t up_action, mcpwm_output_action_t down_action)
|
||||
{
|
||||
mcpwm->channel[op].tz_cfg1.cbcpulse = BIT(0); //immediately
|
||||
if (gen == 0) {
|
||||
mcpwm->channel[op].tz_cfg0.a_cbc_u = up_action;
|
||||
mcpwm->channel[op].tz_cfg0.a_cbc_d = down_action;
|
||||
} else {
|
||||
mcpwm->channel[op].tz_cfg0.b_cbc_u = up_action;
|
||||
mcpwm->channel[op].tz_cfg0.b_cbc_d = down_action;
|
||||
}
|
||||
}
|
||||
|
||||
/********************* Dead Zone (deadtime) *******************/
|
||||
/**
|
||||
* Initialize the dead zone feature.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to initialize, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_deadtime_init(mcpwm_dev_t *mcpwm, int op)
|
||||
{
|
||||
mcpwm->channel[op].db_cfg.fed_upmethod = BIT(0);
|
||||
mcpwm->channel[op].db_cfg.red_upmethod = BIT(0);
|
||||
mcpwm->channel[op].db_cfg.clk_sel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output dead zone mode applying to the outputs of a timer.
|
||||
*
|
||||
* If the desired internal connection is not provided, you can write your own inside this function.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param mode Dead zone mode to use.
|
||||
*/
|
||||
static inline void mcpwm_ll_set_deadtime_mode(mcpwm_dev_t *mcpwm,
|
||||
int op, mcpwm_deadtime_type_t mode)
|
||||
{
|
||||
#define MCPWM_LL_DEADTIME_REG_MASK (MCPWM_DT0_DEB_MODE_M | MCPWM_DT0_A_OUTSWAP_M | MCPWM_DT0_B_OUTSWAP_M | \
|
||||
MCPWM_DT0_RED_INSEL_M | MCPWM_DT0_FED_INSEL_M | MCPWM_DT0_RED_OUTINVERT_M | MCPWM_DT0_FED_OUTINVERT_M | \
|
||||
MCPWM_DT0_A_OUTBYPASS_M | MCPWM_DT0_B_OUTBYPASS_M)
|
||||
|
||||
static uint32_t deadtime_mode_settings[MCPWM_DEADTIME_TYPE_MAX] = {
|
||||
[MCPWM_BYPASS_RED] = 0b010010000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_BYPASS_FED] = 0b100000000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_HIGH_MODE] = 0b000010000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_LOW_MODE] = 0b001110000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE] = 0b001010000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_LOW_COMPLIMENT_MODE] = 0b000101000 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_RED_FED_FROM_PWMXA] = 0b000000011 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_ACTIVE_RED_FED_FROM_PWMXB] = 0b000001011 << MCPWM_DT0_DEB_MODE_S,
|
||||
[MCPWM_DEADTIME_BYPASS] = 0b110000000 << MCPWM_DT0_DEB_MODE_S,
|
||||
};
|
||||
mcpwm->channel[op].db_cfg.val =
|
||||
(mcpwm->channel[op].db_cfg.val & (~MCPWM_LL_DEADTIME_REG_MASK)) | deadtime_mode_settings[mode];
|
||||
|
||||
#undef MCPWM_LL_DEADTIME_REG_MASK
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay of the falling edge on the output.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param fed Falling delay, by PWM main clock.
|
||||
*/
|
||||
static inline void mcpwm_ll_deadtime_set_falling_delay(mcpwm_dev_t *mcpwm, int op, uint32_t fed)
|
||||
{
|
||||
mcpwm->channel[op].db_fed_cfg.fed = fed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay of the rising edge on the output.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param fed Rising delay, by PWM main clock.
|
||||
*/
|
||||
static inline void mcpwm_ll_deadtime_set_rising_delay(mcpwm_dev_t *mcpwm, int op, uint32_t red)
|
||||
{
|
||||
mcpwm->channel[op].db_red_cfg.red = red;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable (bypass) the dead zone feature.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_deadtime_bypass(mcpwm_dev_t *mcpwm, int op)
|
||||
{
|
||||
mcpwm_ll_set_deadtime_mode(mcpwm, op, MCPWM_DEADTIME_BYPASS);
|
||||
}
|
||||
|
||||
/********************* Carrier *******************/
|
||||
/**
|
||||
* Initialize the carrier feature.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_init(mcpwm_dev_t *mcpwm, int op)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.in_invert = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the carrier feature for a timer.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param enable true to enable, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_enable(mcpwm_dev_t *mcpwm, int op, bool enable)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prescale of the carrier timer.
|
||||
*
|
||||
* The carrier period will be Frequency of PWM main clock/(carrier_period+1).
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param carrier_period The prescale of the carrier clock, 0-15.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_set_prescale(mcpwm_dev_t *mcpwm, int op, uint8_t carrier_period)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.prescale = carrier_period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the duty rate of the carrier.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param carrier_duty Duty rate will be (carrier_duty/8)*100%. 0-7.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_set_duty(mcpwm_dev_t *mcpwm, int op, uint8_t carrier_duty)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.duty = carrier_duty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert output of the carrier.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param invert true to invert, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_out_invert(mcpwm_dev_t *mcpwm, int op, bool invert)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.out_invert = invert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the oneshot pulse width of the carrier.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param op The operator to set, 0-2.
|
||||
* @param pulse_width The width of the oneshot pulse, by carrier period. 0 to disable the oneshot pulse.
|
||||
*/
|
||||
static inline void mcpwm_ll_carrier_set_oneshot_width(mcpwm_dev_t *mcpwm, int op, uint8_t pulse_width)
|
||||
{
|
||||
mcpwm->channel[op].carrier_cfg.oshtwth = pulse_width;
|
||||
}
|
||||
|
||||
/********************* Capture *******************/
|
||||
/**
|
||||
* Enable the capture feature for a signal
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param cap_sig Signal to enable, 0-2.
|
||||
* @param enable true to enable, otherwise false.
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_enable(mcpwm_dev_t *mcpwm, int cap_sig, int enable)
|
||||
{
|
||||
if (enable) {
|
||||
mcpwm->cap_timer_cfg.timer_en = 1;
|
||||
mcpwm->cap_cfg_ch[cap_sig].en = 1;
|
||||
} else {
|
||||
mcpwm->cap_cfg_ch[cap_sig].en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the captured value.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param cap_sig Of which signal to get the captured value.
|
||||
* @return The captured value
|
||||
*/
|
||||
static inline uint32_t mcpwm_ll_get_capture_val(mcpwm_dev_t *mcpwm, int cap_sig)
|
||||
{
|
||||
return mcpwm->cap_val_ch[cap_sig];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set capture edge.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param cap_sig Which signal the edge capture is applied.
|
||||
* @return Capture signal edge: 1 - positive edge, 2 - negtive edge
|
||||
*/
|
||||
static inline mcpwm_capture_on_edge_t mcpwm_ll_get_captured_edge(mcpwm_dev_t *mcpwm, int cap_sig)
|
||||
{
|
||||
bool edge;
|
||||
if (cap_sig == 0) {
|
||||
edge = mcpwm->cap_status.cap0_edge;
|
||||
} else if (cap_sig == 1) {
|
||||
edge = mcpwm->cap_status.cap0_edge;
|
||||
} else { //2
|
||||
edge = mcpwm->cap_status.cap0_edge;
|
||||
}
|
||||
return (edge? MCPWM_NEG_EDGE: MCPWM_POS_EDGE);
|
||||
}
|
||||
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_NEG_EDGE, BIT(0));
|
||||
STATIC_HAL_REG_CHECK(MCPWM, MCPWM_POS_EDGE, BIT(1));
|
||||
|
||||
/**
|
||||
* Select the edge to capture.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param cap_sig The signal to capture, 0-2.
|
||||
* @param cap_edge The edge to capture, bitwise.
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_select_edge(mcpwm_dev_t *mcpwm, int cap_sig,
|
||||
mcpwm_capture_on_edge_t cap_edge)
|
||||
{
|
||||
mcpwm->cap_cfg_ch[cap_sig].mode = cap_edge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prescale of the input signal to capture.
|
||||
*
|
||||
* @param mcpwm Address of the MCPWM peripheral registers.
|
||||
* @param cap_sig The prescaled signal to capture, 0-2.
|
||||
* @param prescale Prescal value, 0 to disable.
|
||||
*/
|
||||
static inline void mcpwm_ll_capture_set_prescale(mcpwm_dev_t *mcpwm, int cap_sig, uint32_t prescale)
|
||||
{
|
||||
mcpwm->cap_cfg_ch[cap_sig].prescale = prescale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function, get the `mcpwm_intr_t` interrupt enum of a specific capture signal.
|
||||
*
|
||||
* @param bit x for CAPx.
|
||||
* @return the corresponding `mcpwm_intr_t`.
|
||||
*/
|
||||
static inline mcpwm_intr_t mcpwm_ll_get_cap_intr_def(int bit)
|
||||
{
|
||||
return BIT(bit+MCPWM_CAP0_INT_RAW_S);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
62
components/hal/esp32/include/hal/mpu_ll.h
Normal file
62
components/hal/esp32/include/hal/mpu_ll.h
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "soc/mpu_caps.h"
|
||||
|
||||
#include "xt_instr_macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline uint32_t mpu_ll_id_to_addr(int id)
|
||||
{
|
||||
// vpn - id
|
||||
// 0x00000000 = 0
|
||||
// 0x20000000 = 1
|
||||
// 0x40000000 = 2
|
||||
// 0x60000000 = 3
|
||||
// 0x80000000 = 4
|
||||
// 0xa0000000 = 5
|
||||
// 0xc0000000 = 6
|
||||
// 0xe0000000 = 7
|
||||
return id * SOC_MPU_MIN_REGION_SIZE;
|
||||
}
|
||||
|
||||
static inline void mpu_ll_set_region_rw(uint32_t addr)
|
||||
{
|
||||
WDTLB(0x0, addr); // cached, no allocate
|
||||
}
|
||||
|
||||
static inline void mpu_ll_set_region_rwx(uint32_t addr)
|
||||
{
|
||||
WDTLB(0x2, addr); // bypass cache
|
||||
}
|
||||
|
||||
static inline void mpu_ll_set_region_x(uint32_t addr)
|
||||
{
|
||||
WITLB(0x3, addr); // cached
|
||||
}
|
||||
|
||||
static inline void mpu_ll_set_region_illegal(uint32_t addr)
|
||||
{
|
||||
WITLB(0xF, addr);
|
||||
WDTLB(0xF, addr);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
262
components/hal/esp32/include/hal/mwdt_ll.h
Normal file
262
components/hal/esp32/include/hal/mwdt_ll.h
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for Timer Group register operations.
|
||||
// Note that most of the register operations in this layer are non-atomic operations.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable a particular stage of the MWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param stage Which stage to disable
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_disable_stage(timg_dev_t *hw, uint32_t stage)
|
||||
{
|
||||
switch (stage) {
|
||||
case WDT_STAGE0:
|
||||
hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE1:
|
||||
hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE2:
|
||||
hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE3:
|
||||
hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable MWDT edge interrupt
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable Whether to enable edge interrupt
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_edge_intr(timg_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.edge_int_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable MWDT level interrupt
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable Whether to enable level interrupt
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_level_intr(timg_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.level_int_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the length of the CPU reset action
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param length Length of CPU reset signal
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_cpu_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length)
|
||||
{
|
||||
hw->wdt_config0.cpu_reset_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the length of the system reset action
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param length Length of system reset signal
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_sys_reset_length(timg_dev_t *hw, wdt_reset_sig_length_t length)
|
||||
{
|
||||
hw->wdt_config0.sys_reset_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the MWDT flashboot mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True to enable WDT flashboot mode, false to disable WDT flashboot mode.
|
||||
*
|
||||
* @note Flashboot mode is independent and can trigger a WDT timeout event if the
|
||||
* WDT's enable bit is set to 0. Flashboot mode for TG0 is automatically enabled
|
||||
* on flashboot, and should be disabled by software when flashbooting completes.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_flashboot_en(timg_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the clock prescaler of the MWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param prescaler Prescaler value between 1 to 65535
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_prescaler(timg_dev_t *hw, uint32_t prescaler)
|
||||
{
|
||||
hw->wdt_config1.clk_prescale = prescaler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Feed the MWDT
|
||||
*
|
||||
* Resets the current timer count and current stage.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_feed(timg_dev_t *hw)
|
||||
{
|
||||
hw->wdt_feed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable write protection of the MWDT registers
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw)
|
||||
{
|
||||
hw->wdt_wprotect = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection of the MWDT registers
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw)
|
||||
{
|
||||
hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the MWDT interrupt status.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw)
|
||||
{
|
||||
hw->int_clr_timers.wdt = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the interrupt enable bit for the MWDT interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable Whether to enable the MWDT interrupt
|
||||
*/
|
||||
FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->int_ena.wdt = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
301
components/hal/esp32/include/hal/pcnt_ll.h
Normal file
301
components/hal/esp32/include/hal/pcnt_ll.h
Normal file
@@ -0,0 +1,301 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 PCNT register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/pcnt_periph.h"
|
||||
#include "hal/pcnt_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Get PCNT hardware instance with giving pcnt num
|
||||
#define PCNT_LL_GET_HW(num) (((num) == 0) ? (&PCNT) : NULL)
|
||||
|
||||
/**
|
||||
* @brief Set PCNT counter mode
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @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
|
||||
*/
|
||||
static inline void pcnt_ll_set_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, pcnt_count_mode_t pos_mode, pcnt_count_mode_t neg_mode, pcnt_ctrl_mode_t hctrl_mode, pcnt_ctrl_mode_t lctrl_mode)
|
||||
{
|
||||
typeof(hw->conf_unit[unit].conf0) conf0_reg = hw->conf_unit[unit].conf0;
|
||||
if (channel == 0) {
|
||||
conf0_reg.ch0_pos_mode = pos_mode;
|
||||
conf0_reg.ch0_neg_mode = neg_mode;
|
||||
conf0_reg.ch0_hctrl_mode = hctrl_mode;
|
||||
conf0_reg.ch0_lctrl_mode = lctrl_mode;
|
||||
} else {
|
||||
conf0_reg.ch1_pos_mode = pos_mode;
|
||||
conf0_reg.ch1_neg_mode = neg_mode;
|
||||
conf0_reg.ch1_hctrl_mode = hctrl_mode;
|
||||
conf0_reg.ch1_lctrl_mode = lctrl_mode;
|
||||
}
|
||||
hw->conf_unit[unit].conf0 = conf0_reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get pulse counter value
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit Pulse Counter unit number
|
||||
* @param count Pointer to accept counter value
|
||||
*/
|
||||
static inline void pcnt_ll_get_counter_value(pcnt_dev_t *hw, pcnt_unit_t unit, int16_t *count)
|
||||
{
|
||||
*count = (int16_t) hw->cnt_unit[unit].cnt_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pause PCNT counter of PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
*/
|
||||
static inline void pcnt_ll_counter_pause(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resume counting for PCNT counter
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number, select from pcnt_unit_t
|
||||
*/
|
||||
static inline void pcnt_ll_counter_resume(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (unit * 2))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear and reset PCNT counter value to zero
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number, select from pcnt_unit_t
|
||||
*/
|
||||
static inline void pcnt_ll_counter_clear(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
uint32_t reset_bit = BIT(PCNT_PLUS_CNT_RST_U0_S + (unit * 2));
|
||||
hw->ctrl.val |= reset_bit;
|
||||
hw->ctrl.val &= ~reset_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
*/
|
||||
static inline void pcnt_ll_intr_enable(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable PCNT interrupt for PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
*/
|
||||
static inline void pcnt_ll_intr_disable(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + unit)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PCNT interrupt status
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param status Pointer to accept value
|
||||
*/
|
||||
static inline void pcnt_ll_get_intr_status(pcnt_dev_t *hw, uint32_t *status)
|
||||
{
|
||||
*status = hw->int_st.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear PCNT interrupt status
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param status value to clear interrupt status
|
||||
*/
|
||||
static inline void pcnt_ll_clear_intr_status(pcnt_dev_t *hw, uint32_t status)
|
||||
{
|
||||
hw->int_clr.val = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable PCNT event of PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @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).
|
||||
*/
|
||||
static inline void pcnt_ll_event_enable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
if (evt_type == PCNT_EVT_L_LIM) {
|
||||
hw->conf_unit[unit].conf0.thr_l_lim_en = 1;
|
||||
} else if (evt_type == PCNT_EVT_H_LIM) {
|
||||
hw->conf_unit[unit].conf0.thr_h_lim_en = 1;
|
||||
} else if (evt_type == PCNT_EVT_THRES_0) {
|
||||
hw->conf_unit[unit].conf0.thr_thres0_en = 1;
|
||||
} else if (evt_type == PCNT_EVT_THRES_1) {
|
||||
hw->conf_unit[unit].conf0.thr_thres1_en = 1;
|
||||
} else if (evt_type == PCNT_EVT_ZERO) {
|
||||
hw->conf_unit[unit].conf0.thr_zero_en = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable PCNT event of PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @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).
|
||||
*/
|
||||
static inline void pcnt_ll_event_disable(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
if (evt_type == PCNT_EVT_L_LIM) {
|
||||
hw->conf_unit[unit].conf0.thr_l_lim_en = 0;
|
||||
} else if (evt_type == PCNT_EVT_H_LIM) {
|
||||
hw->conf_unit[unit].conf0.thr_h_lim_en = 0;
|
||||
} else if (evt_type == PCNT_EVT_THRES_0) {
|
||||
hw->conf_unit[unit].conf0.thr_thres0_en = 0;
|
||||
} else if (evt_type == PCNT_EVT_THRES_1) {
|
||||
hw->conf_unit[unit].conf0.thr_thres1_en = 0;
|
||||
} else if (evt_type == PCNT_EVT_ZERO) {
|
||||
hw->conf_unit[unit].conf0.thr_zero_en = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set PCNT event value of PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @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
|
||||
*/
|
||||
static inline void pcnt_ll_set_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
|
||||
{
|
||||
if (evt_type == PCNT_EVT_L_LIM) {
|
||||
hw->conf_unit[unit].conf2.cnt_l_lim = value;
|
||||
} else if (evt_type == PCNT_EVT_H_LIM) {
|
||||
hw->conf_unit[unit].conf2.cnt_h_lim = value;
|
||||
} else if (evt_type == PCNT_EVT_THRES_0) {
|
||||
hw->conf_unit[unit].conf1.cnt_thres0 = value;
|
||||
} else if (evt_type == PCNT_EVT_THRES_1) {
|
||||
hw->conf_unit[unit].conf1.cnt_thres1 = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PCNT event value of PCNT unit
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @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
|
||||
*/
|
||||
static inline void pcnt_ll_get_event_value(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)
|
||||
{
|
||||
if (evt_type == PCNT_EVT_L_LIM) {
|
||||
*value = (int16_t) hw->conf_unit[unit].conf2.cnt_l_lim;
|
||||
} else if (evt_type == PCNT_EVT_H_LIM) {
|
||||
*value = (int16_t) hw->conf_unit[unit].conf2.cnt_h_lim;
|
||||
} else if (evt_type == PCNT_EVT_THRES_0) {
|
||||
*value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres0;
|
||||
} else if (evt_type == PCNT_EVT_THRES_1) {
|
||||
*value = (int16_t) hw->conf_unit[unit].conf1.cnt_thres1;
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set PCNT filter value
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
* @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
|
||||
* Any pulses lasting shorter than this will be ignored when the filter is enabled.
|
||||
* @note
|
||||
* filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
|
||||
*/
|
||||
static inline void pcnt_ll_set_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t filter_val)
|
||||
{
|
||||
hw->conf_unit[unit].conf0.filter_thres = filter_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PCNT filter value
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
* @param filter_val Pointer to accept PCNT filter value.
|
||||
*/
|
||||
static inline void pcnt_ll_get_filter_value(pcnt_dev_t *hw, pcnt_unit_t unit, uint16_t *filter_val)
|
||||
{
|
||||
*filter_val = hw->conf_unit[unit].conf0.filter_thres;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable PCNT input filter
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
*/
|
||||
static inline void pcnt_ll_filter_enable(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->conf_unit[unit].conf0.filter_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable PCNT input filter
|
||||
*
|
||||
* @param hw Peripheral PCNT hardware instance address.
|
||||
* @param unit PCNT unit number
|
||||
*/
|
||||
static inline void pcnt_ll_filter_disable(pcnt_dev_t *hw, pcnt_unit_t unit)
|
||||
{
|
||||
hw->conf_unit[unit].conf0.filter_en = 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
307
components/hal/esp32/include/hal/rmt_ll.h
Normal file
307
components/hal/esp32/include/hal/rmt_ll.h
Normal file
@@ -0,0 +1,307 @@
|
||||
// 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 <stdbool.h>
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "soc/rmt_caps.h"
|
||||
|
||||
#define RMT_LL_HW_BASE (&RMT)
|
||||
#define RMT_LL_MEM_BASE (&RMTMEM)
|
||||
|
||||
static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable)
|
||||
{
|
||||
dev->conf_ch[0].conf0.clk_en = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_reset_counter_clock_div(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.ref_cnt_rst = 1;
|
||||
dev->conf_ch[channel].conf1.ref_cnt_rst = 0;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_reset_tx_pointer(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_reset_rx_pointer(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
dev->conf_ch[channel].conf1.mem_wr_rst = 0;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_start_tx(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.tx_start = 1;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_stop_tx(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
RMTMEM.chan[channel].data32[0].val = 0;
|
||||
dev->conf_ch[channel].conf1.tx_start = 0;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
dev->conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_rx(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.rx_en = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable)
|
||||
{
|
||||
dev->conf_ch[0].conf0.mem_pd = enable; // Only conf0 register of channel0 has `mem_pd`
|
||||
}
|
||||
|
||||
static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev)
|
||||
{
|
||||
return dev->conf_ch[0].conf0.mem_pd; // Only conf0 register of channel0 has `mem_pd`
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
|
||||
{
|
||||
dev->conf_ch[channel].conf0.mem_size = block_num;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf0.mem_size;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_counter_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
|
||||
{
|
||||
dev->conf_ch[channel].conf0.div_cnt = div;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_counter_clock_div(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
uint32_t div = dev->conf_ch[channel].conf0.div_cnt;
|
||||
return div == 0 ? 256 : div;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_tx_pingpong(rmt_dev_t *dev, bool enable)
|
||||
{
|
||||
dev->apb_conf.mem_tx_wrap_en = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable)
|
||||
{
|
||||
dev->apb_conf.fifo_mask = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_rx_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
|
||||
{
|
||||
dev->conf_ch[channel].conf0.idle_thres = thres;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_rx_idle_thres(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf0.idle_thres;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.mem_owner = owner;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_mem_owner(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf1.mem_owner;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_tx_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.tx_conti_mode = enable;
|
||||
}
|
||||
|
||||
static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf1.tx_conti_mode;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_rx_filter(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.rx_filter_en = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_rx_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.rx_filter_thres = thres;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_counter_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.ref_always_on = src;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_counter_clock_src(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf1.ref_always_on;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_tx_idle(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.idle_out_en = enable;
|
||||
}
|
||||
|
||||
static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf1.idle_out_en;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_tx_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
|
||||
{
|
||||
dev->conf_ch[channel].conf1.idle_out_lv = level;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_tx_idle_level(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->conf_ch[channel].conf1.idle_out_lv;
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_channel_status(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
return dev->status_ch[channel];
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_tx_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
|
||||
{
|
||||
dev->tx_lim_ch[channel].limit = limit;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel * 3));
|
||||
dev->int_ena.val |= (enable << (channel * 3));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel * 3 + 1));
|
||||
dev->int_ena.val |= (enable << (channel * 3 + 1));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel * 3 + 2));
|
||||
dev->int_ena.val |= (enable << (channel * 3 + 2));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->int_ena.val &= ~(1 << (channel + 24));
|
||||
dev->int_ena.val |= (enable << (channel + 24));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel * 3));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel * 3 + 1));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_clear_err_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel * 3 + 2));
|
||||
}
|
||||
|
||||
static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
|
||||
{
|
||||
dev->int_clr.val = (1 << (channel + 24));
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_tx_end_interrupt_status(rmt_dev_t *dev)
|
||||
{
|
||||
uint32_t status = dev->int_st.val;
|
||||
return ((status & 0x01) >> 0) | ((status & 0x08) >> 2) | ((status & 0x40) >> 4) | ((status & 0x200) >> 6) |
|
||||
((status & 0x1000) >> 8) | ((status & 0x8000) >> 10) | ((status & 0x40000) >> 12) | ((status & 0x200000) >> 14);
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_rx_end_interrupt_status(rmt_dev_t *dev)
|
||||
{
|
||||
uint32_t status = dev->int_st.val;
|
||||
return ((status & 0x02) >> 1) | ((status & 0x10) >> 3) | ((status & 0x80) >> 5) | ((status & 0x400) >> 7) |
|
||||
((status & 0x2000) >> 9) | ((status & 0x10000) >> 11) | ((status & 0x80000) >> 13) | ((status & 0x400000) >> 15);
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_err_interrupt_status(rmt_dev_t *dev)
|
||||
{
|
||||
uint32_t status = dev->int_st.val;
|
||||
return ((status & 0x04) >> 2) | ((status & 0x20) >> 4) | ((status & 0x100) >> 6) | ((status & 0x800) >> 8) |
|
||||
((status & 0x4000) >> 10) | ((status & 0x20000) >> 12) | ((status & 0x100000) >> 14) | ((status & 0x800000) >> 16);
|
||||
}
|
||||
|
||||
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
|
||||
{
|
||||
uint32_t status = dev->int_st.val;
|
||||
return (status & 0xFF000000) >> 24;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_tx_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
|
||||
{
|
||||
dev->carrier_duty_ch[channel].high = high_ticks;
|
||||
dev->carrier_duty_ch[channel].low = low_ticks;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks)
|
||||
{
|
||||
*high_ticks = dev->carrier_duty_ch[channel].high;
|
||||
*low_ticks = dev->carrier_duty_ch[channel].low;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_enable_carrier(rmt_dev_t *dev, uint32_t channel, bool enable)
|
||||
{
|
||||
dev->conf_ch[channel].conf0.carrier_en = enable;
|
||||
}
|
||||
|
||||
static inline void rmt_ll_set_carrier_on_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
|
||||
{
|
||||
dev->conf_ch[channel].conf0.carrier_out_lv = level;
|
||||
}
|
||||
|
||||
//Writes items to the specified TX channel memory with the given offset and writen length.
|
||||
//the caller should ensure that (length + off) <= (memory block * SOC_RMT_CHANNEL_MEM_WORDS)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* Following Low Level APIs only used for backward compatible, will be deprecated in the future!
|
||||
***********************************************************************************************/
|
||||
|
||||
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
|
55
components/hal/esp32/include/hal/rtc_cntl_ll.h
Normal file
55
components/hal/esp32/include/hal/rtc_cntl_ll.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t)
|
||||
{
|
||||
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX);
|
||||
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32);
|
||||
}
|
||||
|
||||
static inline void rtc_cntl_ll_ext1_clear_wakeup_pins(void)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR);
|
||||
}
|
||||
|
||||
static inline uint32_t rtc_cntl_ll_ext1_get_wakeup_pins(void)
|
||||
{
|
||||
return REG_GET_FIELD(RTC_CNTL_EXT_WAKEUP1_STATUS_REG, RTC_CNTL_EXT_WAKEUP1_STATUS);
|
||||
}
|
||||
|
||||
static inline void rtc_cntl_ll_ext1_set_wakeup_pins(uint32_t mask, int mode)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_SEL, mask);
|
||||
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
|
||||
mode, RTC_CNTL_EXT_WAKEUP1_LV_S);
|
||||
}
|
||||
|
||||
static inline void rtc_cntl_ll_ulp_wakeup_enable(void)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_WAKEUP_FORCE_EN);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
366
components/hal/esp32/include/hal/rtc_io_ll.h
Normal file
366
components/hal/esp32/include/hal/rtc_io_ll.h
Normal file
@@ -0,0 +1,366 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "soc/rtc_io_periph.h"
|
||||
#include "hal/rtc_io_types.h"
|
||||
#include "hal/gpio_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */
|
||||
RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */
|
||||
} rtcio_ll_func_t;
|
||||
|
||||
typedef enum {
|
||||
RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */
|
||||
RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */
|
||||
RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */
|
||||
} rtcio_ll_wake_type_t;
|
||||
|
||||
typedef enum {
|
||||
RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */
|
||||
RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */
|
||||
} rtcio_ll_out_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Select the rtcio function.
|
||||
*
|
||||
* @note The RTC function must be selected before the pad analog function is enabled.
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @param func Select pin function.
|
||||
*/
|
||||
static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func)
|
||||
{
|
||||
if (func == RTCIO_FUNC_RTC) {
|
||||
// 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module.
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
|
||||
//0:RTC FUNCTION 1,2,3:Reserved
|
||||
SET_PERI_REG_BITS(rtc_io_desc[rtcio_num].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, SOC_PIN_FUNC_RTC_IO, rtc_io_desc[rtcio_num].func);
|
||||
} else if (func == RTCIO_FUNC_DIGITAL) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rtcio output.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_output_enable(int rtcio_num)
|
||||
{
|
||||
RTCIO.enable_w1ts.w1ts = (1U << rtcio_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rtcio output.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_output_disable(int rtcio_num)
|
||||
{
|
||||
RTCIO.enable_w1tc.w1tc = (1U << rtcio_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set RTCIO output level.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @param level 0: output low; ~0: output high.
|
||||
*/
|
||||
static inline void rtcio_ll_set_level(int rtcio_num, uint32_t level)
|
||||
{
|
||||
if (level) {
|
||||
RTCIO.out_w1ts.w1ts = (1U << rtcio_num);
|
||||
} else {
|
||||
RTCIO.out_w1tc.w1tc = (1U << rtcio_num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rtcio input.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_input_enable(int rtcio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].ie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rtcio input.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_input_disable(int rtcio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].ie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RTCIO input level.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @return 0: input low; ~0: input high.
|
||||
*/
|
||||
static inline uint32_t rtcio_ll_get_level(int rtcio_num)
|
||||
{
|
||||
return (uint32_t)(RTCIO.in_val.in >> rtcio_num) & 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set RTC GPIO pad drive capability
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @param strength Drive capability of the pad. Range: 0 ~ 3.
|
||||
*/
|
||||
static inline void rtcio_ll_set_drive_capability(int rtcio_num, uint32_t strength)
|
||||
{
|
||||
if (rtc_io_desc[rtcio_num].drv_v) {
|
||||
SET_PERI_REG_BITS(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].drv_v, strength, rtc_io_desc[rtcio_num].drv_s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get RTC GPIO pad drive capability.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @return Drive capability of the pad. Range: 0 ~ 3.
|
||||
*/
|
||||
static inline uint32_t rtcio_ll_get_drive_capability(int rtcio_num)
|
||||
{
|
||||
return GET_PERI_REG_BITS2(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].drv_v, rtc_io_desc[rtcio_num].drv_s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set RTC GPIO pad output mode.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @return mode Output mode.
|
||||
*/
|
||||
static inline void rtcio_ll_output_mode_set(int rtcio_num, rtcio_ll_out_mode_t mode)
|
||||
{
|
||||
RTCIO.pin[rtcio_num].pad_driver = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC GPIO pullup enable.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_pullup_enable(int rtcio_num)
|
||||
{
|
||||
if (rtc_io_desc[rtcio_num].pullup) {
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pullup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC GPIO pullup disable.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_pullup_disable(int rtcio_num)
|
||||
{
|
||||
if (rtc_io_desc[rtcio_num].pullup) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pullup);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC GPIO pulldown enable.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_pulldown_enable(int rtcio_num)
|
||||
{
|
||||
if (rtc_io_desc[rtcio_num].pulldown) {
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pulldown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC GPIO pulldown disable.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_pulldown_disable(int rtcio_num)
|
||||
{
|
||||
if (rtc_io_desc[rtcio_num].pulldown) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].pulldown);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable force hold function for RTC IO pad.
|
||||
*
|
||||
* Enabling HOLD function will cause the pad to lock current status, such as,
|
||||
* input/output enable, input/output value, function, drive strength values.
|
||||
* This function is useful when going into light or deep sleep mode to prevent
|
||||
* the pin configuration from changing.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_force_hold_enable(int rtcio_num)
|
||||
{
|
||||
REG_SET_BIT(RTC_CNTL_HOLD_FORCE_REG, rtc_io_desc[rtcio_num].hold_force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable hold function on an RTC IO pad
|
||||
*
|
||||
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_force_hold_disable(int rtcio_num)
|
||||
{
|
||||
REG_CLR_BIT(RTC_CNTL_HOLD_FORCE_REG, rtc_io_desc[rtcio_num].hold_force);
|
||||
REG_CLR_BIT(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable force hold function for RTC IO pad.
|
||||
*
|
||||
* Enabling HOLD function will cause the pad to lock current status, such as,
|
||||
* input/output enable, input/output value, function, drive strength values.
|
||||
* This function is useful when going into light or deep sleep mode to prevent
|
||||
* the pin configuration from changing.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_force_hold_all(void)
|
||||
{
|
||||
SET_PERI_REG_BITS(RTC_CNTL_HOLD_FORCE_REG, 0x3FFFF, 0x3FFFF, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable hold function on an RTC IO pad
|
||||
*
|
||||
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_force_unhold_all(void)
|
||||
{
|
||||
SET_PERI_REG_BITS(RTC_CNTL_HOLD_FORCE_REG, 0x3FFFF, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable wakeup function and set wakeup type from light sleep status for rtcio.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
* @param type Wakeup on high level or low level.
|
||||
*/
|
||||
static inline void rtcio_ll_wakeup_enable(int rtcio_num, rtcio_ll_wake_type_t type)
|
||||
{
|
||||
RTCIO.pin[rtcio_num].wakeup_enable = 0x1;
|
||||
RTCIO.pin[rtcio_num].int_type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable wakeup function from light sleep status for rtcio.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_wakeup_disable(int rtcio_num)
|
||||
{
|
||||
RTCIO.pin[rtcio_num].wakeup_enable = 0;
|
||||
RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rtc io output in deep sleep.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num)
|
||||
{
|
||||
if (rtc_io_desc[gpio_num].slpoe) {
|
||||
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rtc io output in deep sleep.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_in_sleep_disable_output(gpio_num_t gpio_num)
|
||||
{
|
||||
if (rtc_io_desc[gpio_num].slpoe) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rtc io input in deep sleep.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_in_sleep_enable_input(gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rtc io input in deep sleep.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_in_sleep_disable_input(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable rtc io keep another setting in deep sleep.
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num)
|
||||
{
|
||||
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rtc io keep another setting in deep sleep. (Default)
|
||||
*
|
||||
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
|
||||
*/
|
||||
static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num)
|
||||
{
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
|
||||
}
|
||||
|
||||
static inline void rtcio_ll_ext0_set_wakeup_pin(int rtcio_num, int level)
|
||||
{
|
||||
REG_SET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL, rtcio_num);
|
||||
// Set level which will trigger wakeup
|
||||
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
|
||||
level , RTC_CNTL_EXT_WAKEUP0_LV_S);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
297
components/hal/esp32/include/hal/rwdt_ll.h
Normal file
297
components/hal/esp32/include/hal/rwdt_ll.h
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for Timer Group register operations.
|
||||
// Note that most of the register operations in this layer are non-atomic operations.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/wdt_types.h"
|
||||
#include "soc/rtc_cntl_periph.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
//Type check wdt_stage_action_t
|
||||
_Static_assert(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
|
||||
_Static_assert(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
|
||||
_Static_assert(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
|
||||
_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
|
||||
_Static_assert(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
|
||||
//Type check wdt_reset_sig_length_t
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enable the RWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
hw->wdt_config0.en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the RWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @note This function does not disable the flashboot mode. Therefore, given that
|
||||
* the MWDT is disabled using this function, a timeout can still occur
|
||||
* if the flashboot mode is simultaneously enabled.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
hw->wdt_config0.en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the RWDT is enabled
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @return True if RTC WDT is enabled
|
||||
*/
|
||||
FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
return (hw->wdt_config0.en) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configure a particular stage of the RWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param stage Which stage to configure
|
||||
* @param timeout Number of timer ticks for the stage to timeout
|
||||
* @param behavior What action to take when the stage times out
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior)
|
||||
{
|
||||
switch (stage) {
|
||||
case WDT_STAGE0:
|
||||
hw->wdt_config0.stg0 = behavior;
|
||||
hw->wdt_config1 = timeout_ticks;
|
||||
break;
|
||||
case WDT_STAGE1:
|
||||
hw->wdt_config0.stg1 = behavior;
|
||||
hw->wdt_config2 = timeout_ticks;
|
||||
break;
|
||||
case WDT_STAGE2:
|
||||
hw->wdt_config0.stg2 = behavior;
|
||||
hw->wdt_config3 = timeout_ticks;
|
||||
break;
|
||||
case WDT_STAGE3:
|
||||
hw->wdt_config0.stg3 = behavior;
|
||||
hw->wdt_config4 = timeout_ticks;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable a particular stage of the RWDT
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param stage Which stage to disable
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage)
|
||||
{
|
||||
switch (stage) {
|
||||
case WDT_STAGE0:
|
||||
hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE1:
|
||||
hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE2:
|
||||
hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
case WDT_STAGE3:
|
||||
hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable RWDT edge interrupt
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable Whether to enable edge interrupt
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_edge_intr(rtc_cntl_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.edge_int_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable or disable RWDT level interrupt
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable Whether to enable level interrupt
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_level_intr(rtc_cntl_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.level_int_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the length of the CPU reset action
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param length Length of CPU reset signal
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
|
||||
{
|
||||
hw->wdt_config0.cpu_reset_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the length of the system reset action
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param length Length of system reset signal
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
|
||||
{
|
||||
hw->wdt_config0.sys_reset_length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the RWDT flashboot mode.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode.
|
||||
*
|
||||
* @note Flashboot mode is independent and can trigger a WDT timeout event if the
|
||||
* WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled
|
||||
* on flashboot, and should be disabled by software when flashbooting completes.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable True to enable CPU0 to be reset, false to disable.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable True to enable CPU1 to be reset, false to disable.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable the RWDT pause during sleep functionality
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable True to enable, false to disable.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Feed the RWDT
|
||||
*
|
||||
* Resets the current timer count and current stage.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
hw->wdt_feed.feed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable write protection of the RWDT registers
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
hw->wdt_wprotect = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable write protection of the RWDT registers
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the RWDT interrupt.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @param enable True to enable RWDT interrupt, false to disable.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->int_ena.rtc_wdt = (enable) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the RWDT interrupt has been triggered
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
* @return True if the RWDT interrupt was triggered
|
||||
*/
|
||||
FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw)
|
||||
{
|
||||
return (hw->int_st.rtc_wdt) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the RWDT interrupt status.
|
||||
*
|
||||
* @param hw Start address of the peripheral registers.
|
||||
*/
|
||||
FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw)
|
||||
{
|
||||
hw->int_clr.rtc_wdt = 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
73
components/hal/esp32/include/hal/sigmadelta_ll.h
Normal file
73
components/hal/esp32/include/hal/sigmadelta_ll.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// 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)
|
||||
{
|
||||
// The clk enable register does not exist on ESP32.
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set Sigma-delta channel duty.
|
||||
*
|
||||
* @param hw Peripheral SIGMADELTA hardware instance address.
|
||||
* @param channel Sigma-delta channel number
|
||||
* @param duty Sigma-delta duty of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90.
|
||||
* The waveform is more like a random one in this range.
|
||||
*/
|
||||
static inline void sigmadelta_ll_set_duty(gpio_sd_dev_t *hw, sigmadelta_channel_t channel, int8_t duty)
|
||||
{
|
||||
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
|
54
components/hal/esp32/include/hal/soc_ll.h
Normal file
54
components/hal/esp32/include/hal/soc_ll.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline void soc_ll_stall_core(int core)
|
||||
{
|
||||
const int rtc_cntl_c1_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_M, RTC_CNTL_SW_STALL_APPCPU_C1_M};
|
||||
const int rtc_cntl_c1_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_S, RTC_CNTL_SW_STALL_APPCPU_C1_S};
|
||||
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_M, RTC_CNTL_SW_STALL_APPCPU_C0_M};
|
||||
const int rtc_cntl_c0_s[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_S, RTC_CNTL_SW_STALL_APPCPU_C0_S};
|
||||
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m[core]);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21 << rtc_cntl_c1_s[core]);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m[core]);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2 << rtc_cntl_c0_s[core]);
|
||||
}
|
||||
|
||||
static inline void soc_ll_unstall_core(int core)
|
||||
{
|
||||
const int rtc_cntl_c1_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C1_M, RTC_CNTL_SW_STALL_APPCPU_C1_M};
|
||||
const int rtc_cntl_c0_m[SOC_CPU_CORES_NUM] = {RTC_CNTL_SW_STALL_PROCPU_C0_M, RTC_CNTL_SW_STALL_APPCPU_C0_M};
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m[core]);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m[core]);
|
||||
}
|
||||
|
||||
static inline void soc_ll_reset_core(int core)
|
||||
{
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
|
||||
core == 0 ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
393
components/hal/esp32/include/hal/spi_flash_ll.h
Normal file
393
components/hal/esp32/include/hal/spi_flash_ll.h
Normal file
@@ -0,0 +1,393 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in 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
|
||||
|
||||
//Supported clock register values
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_5MHZ ((spi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_10MHZ ((spi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_20MHZ ((spi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_26MHZ ((spi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_40MHZ ((spi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz
|
||||
#define SPI_FLASH_LL_CLKREG_VAL_80MHZ ((spi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
|
||||
|
||||
/// Get the start address of SPI peripheral registers by the host ID
|
||||
#define spi_flash_ll_get_hw(host_id) ( ((host_id)==SPI1_HOST) ? &SPI1 :(\
|
||||
((host_id)==SPI2_HOST) ? &SPI2 :(\
|
||||
((host_id)==SPI3_HOST) ? &SPI3 :(\
|
||||
{abort();(spi_dev_t*)0;}\
|
||||
))) )
|
||||
#define spi_flash_ll_hw_get_id(dev) ( ((dev) == &SPI1) ? SPI1_HOST :(\
|
||||
((dev) == &SPI2) ? SPI2_HOST :(\
|
||||
((dev) == &SPI3) ? SPI3_HOST :(\
|
||||
-1\
|
||||
))) )
|
||||
|
||||
/// Empty function to be compatible with new version chips.
|
||||
#define spi_flash_ll_set_dummy_out(dev, out_en, out_lev)
|
||||
|
||||
/// type to store pre-calculated register value in above layers
|
||||
typedef typeof(SPI1.clock) spi_flash_ll_clock_reg_t;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Control
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Reset peripheral registers before configuration and starting control
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_flash_ll_reset(spi_dev_t *dev)
|
||||
{
|
||||
dev->user.val = 0;
|
||||
dev->ctrl.val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the previous operation is done.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return true if last command is done, otherwise false.
|
||||
*/
|
||||
static inline bool spi_flash_ll_cmd_is_done(const spi_dev_t *dev)
|
||||
{
|
||||
return (dev->cmd.val == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the flash chip.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_flash_ll_erase_chip(spi_dev_t *dev)
|
||||
{
|
||||
dev->cmd.flash_ce = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the sector, the address should be set by spi_flash_ll_set_address.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_flash_ll_erase_sector(spi_dev_t *dev)
|
||||
{
|
||||
dev->ctrl.val = 0;
|
||||
dev->cmd.flash_se = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the block, the address should be set by spi_flash_ll_set_address.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_flash_ll_erase_block(spi_dev_t *dev)
|
||||
{
|
||||
dev->cmd.flash_be = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable write protection for the flash chip.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param wp true to enable the protection, false to disable (write enable).
|
||||
*/
|
||||
static inline void spi_flash_ll_set_write_protect(spi_dev_t *dev, bool wp)
|
||||
{
|
||||
if (wp) {
|
||||
dev->cmd.flash_wrdi = 1;
|
||||
} else {
|
||||
dev->cmd.flash_wren = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the read data from the buffer after ``spi_flash_ll_read`` is done.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param buffer Buffer to hold the output data
|
||||
* @param read_len Length to get out of the buffer
|
||||
*/
|
||||
static inline void spi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len)
|
||||
{
|
||||
if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) {
|
||||
// If everything is word-aligned, do a faster memcpy
|
||||
memcpy(buffer, (void *)dev->data_buf, read_len);
|
||||
} else {
|
||||
// Otherwise, slow(er) path copies word by word
|
||||
int copy_len = read_len;
|
||||
for (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 spi_flash_ll_write_word(spi_dev_t *dev, uint32_t word)
|
||||
{
|
||||
dev->data_buf[0] = word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data to be written in the data buffer.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param buffer Buffer holding the data
|
||||
* @param length Length of data in bytes.
|
||||
*/
|
||||
static inline void spi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length)
|
||||
{
|
||||
// Load data registers, word at a time
|
||||
int num_words = (length + 3) >> 2;
|
||||
for (int i = 0; i < num_words; i++) {
|
||||
uint32_t word = 0;
|
||||
uint32_t word_len = MIN(length, sizeof(word));
|
||||
memcpy(&word, buffer, word_len);
|
||||
dev->data_buf[i] = word;
|
||||
length -= word_len;
|
||||
buffer = (void *)((intptr_t)buffer + word_len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Program a page of the flash chip. Call ``spi_flash_ll_set_address`` before
|
||||
* this to set the address to program.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param buffer Buffer holding the data to program
|
||||
* @param length Length to program.
|
||||
*/
|
||||
static inline void spi_flash_ll_program_page(spi_dev_t *dev, const void *buffer, uint32_t length)
|
||||
{
|
||||
dev->user.usr_dummy = 0;
|
||||
spi_flash_ll_set_buffer_data(dev, buffer, length);
|
||||
dev->cmd.flash_pp = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases,
|
||||
* should be configured before this is called.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_flash_ll_user_start(spi_dev_t *dev)
|
||||
{
|
||||
dev->cmd.usr = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the host is idle to perform new commands.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return true if the host is idle, otherwise false
|
||||
*/
|
||||
static inline bool spi_flash_ll_host_idle(const spi_dev_t *dev)
|
||||
{
|
||||
return dev->ext2.st != 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Select which pin to use for the flash
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins.
|
||||
*/
|
||||
static inline void spi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin)
|
||||
{
|
||||
dev->pin.cs0_dis = (pin != 0);
|
||||
dev->pin.cs1_dis = (pin != 1);
|
||||
dev->pin.cs2_dis = (pin != 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the read io mode.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param read_mode I/O mode to use in the following transactions.
|
||||
*/
|
||||
static inline void spi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode)
|
||||
{
|
||||
typeof (dev->ctrl) ctrl = dev->ctrl;
|
||||
ctrl.val &= ~(SPI_FREAD_QIO_M | SPI_FREAD_QUAD_M | SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M);
|
||||
ctrl.val |= SPI_FASTRD_MODE_M;
|
||||
switch (read_mode) {
|
||||
case SPI_FLASH_FASTRD:
|
||||
//the default option
|
||||
break;
|
||||
case SPI_FLASH_QIO:
|
||||
ctrl.fread_qio = 1;
|
||||
break;
|
||||
case SPI_FLASH_QOUT:
|
||||
ctrl.fread_quad = 1;
|
||||
break;
|
||||
case SPI_FLASH_DIO:
|
||||
ctrl.fread_dio = 1;
|
||||
break;
|
||||
case SPI_FLASH_DOUT:
|
||||
ctrl.fread_dual = 1;
|
||||
break;
|
||||
case SPI_FLASH_SLOWRD:
|
||||
ctrl.fastrd_mode = 0;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
dev->ctrl = ctrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set clock frequency to work at.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param clock_val pointer to the clock value to set
|
||||
*/
|
||||
static inline void spi_flash_ll_set_clock(spi_dev_t *dev, spi_flash_ll_clock_reg_t *clock_val)
|
||||
{
|
||||
dev->clock = *clock_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input length, in bits.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param bitlen Length of input, in bits.
|
||||
*/
|
||||
static inline void spi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
|
||||
{
|
||||
dev->user.usr_miso = bitlen > 0;
|
||||
dev->miso_dlen.usr_miso_dbitlen = bitlen ? (bitlen - 1) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output length, in bits (not including command, address and dummy
|
||||
* phases)
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param bitlen Length of output, in bits.
|
||||
*/
|
||||
static inline void spi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
|
||||
{
|
||||
dev->user.usr_mosi = bitlen > 0;
|
||||
dev->mosi_dlen.usr_mosi_dbitlen = bitlen ? (bitlen - 1) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the command with fixed length (8 bits).
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param command Command to send
|
||||
*/
|
||||
static inline void spi_flash_ll_set_command8(spi_dev_t *dev, uint8_t command)
|
||||
{
|
||||
dev->user.usr_command = 1;
|
||||
typeof(dev->user2) user2 = {
|
||||
.usr_command_value = command,
|
||||
.usr_command_bitlen = (8 - 1),
|
||||
};
|
||||
dev->user2 = user2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address length that is set in register, in bits.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
*
|
||||
*/
|
||||
static inline int spi_flash_ll_get_addr_bitlen(spi_dev_t *dev)
|
||||
{
|
||||
return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write...
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param bitlen Length of the address, in bits
|
||||
*/
|
||||
static inline void spi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen)
|
||||
{
|
||||
dev->user1.usr_addr_bitlen = (bitlen - 1);
|
||||
dev->user.usr_addr = bitlen ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address to send in user command mode. Should be called before commands that requires the address e.g. erase sector, read, write...
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param addr Address to send
|
||||
*/
|
||||
static inline void spi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, int bit_len)
|
||||
{
|
||||
dev->addr = (addr << (32 - bit_len));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param addr Address to send
|
||||
*/
|
||||
static inline void spi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr)
|
||||
{
|
||||
dev->addr = addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of dummy cycles.
|
||||
*
|
||||
* @param dev Beginning address of the peripheral registers.
|
||||
* @param dummy_n Cycles of dummy phases
|
||||
*/
|
||||
static inline void spi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
|
||||
{
|
||||
dev->user.usr_dummy = dummy_n ? 1 : 0;
|
||||
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
884
components/hal/esp32/include/hal/spi_ll.h
Normal file
884
components/hal/esp32/include/hal/spi_ll.h
Normal file
@@ -0,0 +1,884 @@
|
||||
// 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
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 SPI register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/hal_defs.h"
|
||||
#include "soc/spi_periph.h"
|
||||
#include "esp32/rom/lldesc.h"
|
||||
#include <string.h>
|
||||
#include <esp_types.h>
|
||||
#include <stdlib.h> //for abs()
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Registers to reset during initialization. Don't use in app.
|
||||
#define SPI_LL_RST_MASK (SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST)
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_INT_EN | SPI_SLV_WR_STA_DONE | SPI_SLV_RD_STA_DONE | SPI_SLV_WR_BUF_DONE | SPI_SLV_RD_BUF_DONE)
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)data<<(32-len))
|
||||
|
||||
#define SPI_LL_GET_HW(ID) ((ID)==0? &SPI1:((ID)==1? &SPI2 : &SPI3))
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
* calculation needs long time, it should be calculated during initialization and
|
||||
* stored somewhere to be quickly used.
|
||||
*/
|
||||
typedef uint32_t spi_ll_clock_val_t;
|
||||
|
||||
/** IO modes supported by the master. */
|
||||
typedef enum {
|
||||
SPI_LL_IO_MODE_NORMAL = 0, ///< 1-bit mode for all phases
|
||||
SPI_LL_IO_MODE_DIO, ///< 2-bit mode for address and data phases, 1-bit mode for command phase
|
||||
SPI_LL_IO_MODE_DUAL, ///< 2-bit mode for data phases only, 1-bit mode for command and address phases
|
||||
SPI_LL_IO_MODE_QIO, ///< 4-bit mode for address and data phases, 1-bit mode for command phase
|
||||
SPI_LL_IO_MODE_QUAD, ///< 4-bit mode for data phases only, 1-bit mode for command and address phases
|
||||
} spi_ll_io_mode_t;
|
||||
|
||||
/// Interrupt type for different working pattern
|
||||
typedef enum {
|
||||
SPI_LL_INT_TYPE_NORMAL = 0, ///< Typical pattern, only wait for trans done
|
||||
} spi_ll_slave_intr_type;
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Control
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Initialize SPI peripheral (master).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_master_init(spi_dev_t *hw)
|
||||
{
|
||||
//Reset DMA
|
||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||
hw->dma_out_link.start = 0;
|
||||
hw->dma_in_link.start = 0;
|
||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||
//Reset timing
|
||||
hw->ctrl2.val = 0;
|
||||
|
||||
//use all 64 bytes of the buffer
|
||||
hw->user.usr_miso_highpart = 0;
|
||||
hw->user.usr_mosi_highpart = 0;
|
||||
|
||||
//Disable unneeded ints
|
||||
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize SPI peripheral (slave).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_slave_init(spi_dev_t *hw)
|
||||
{
|
||||
//Configure slave
|
||||
hw->clock.val = 0;
|
||||
hw->user.val = 0;
|
||||
hw->ctrl.val = 0;
|
||||
hw->slave.wr_rd_buf_en = 1; //no sure if needed
|
||||
hw->user.doutdin = 1; //we only support full duplex
|
||||
hw->user.sio = 0;
|
||||
hw->slave.slave_mode = 1;
|
||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||
hw->dma_out_link.start = 0;
|
||||
hw->dma_in_link.start = 0;
|
||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||
hw->slave.sync_reset = 1;
|
||||
hw->slave.sync_reset = 0;
|
||||
//use all 64 bytes of the buffer
|
||||
hw->user.usr_miso_highpart = 0;
|
||||
hw->user.usr_mosi_highpart = 0;
|
||||
|
||||
//Disable unneeded ints
|
||||
hw->slave.val &= ~SPI_LL_UNUSED_INT_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset TX and RX DMAs.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_reset_dma(spi_dev_t *hw)
|
||||
{
|
||||
//Reset DMA peripheral
|
||||
hw->dma_conf.val |= SPI_LL_RST_MASK;
|
||||
hw->dma_out_link.start = 0;
|
||||
hw->dma_in_link.start = 0;
|
||||
hw->dma_conf.val &= ~SPI_LL_RST_MASK;
|
||||
hw->dma_conf.out_data_burst_en = 1;
|
||||
hw->dma_conf.indscr_burst_en = 1;
|
||||
hw->dma_conf.outdscr_burst_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start RX DMA.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address of the beginning DMA descriptor.
|
||||
*/
|
||||
static inline void spi_ll_rxdma_start(spi_dev_t *hw, lldesc_t *addr)
|
||||
{
|
||||
hw->dma_in_link.addr = (int) addr & 0xFFFFF;
|
||||
hw->dma_in_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start TX DMA.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address of the beginning DMA descriptor.
|
||||
*/
|
||||
static inline void spi_ll_txdma_start(spi_dev_t *hw, lldesc_t *addr)
|
||||
{
|
||||
hw->dma_out_link.addr = (int) addr & 0xFFFFF;
|
||||
hw->dma_out_link.start = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to SPI buffer.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param buffer_to_send Data address to copy to the buffer.
|
||||
* @param bitlen Length to copy, in bits.
|
||||
*/
|
||||
static inline void spi_ll_write_buffer(spi_dev_t *hw, const uint8_t *buffer_to_send, size_t bitlen)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Use memcpy to get around alignment issues for txdata
|
||||
uint32_t word;
|
||||
memcpy(&word, &buffer_to_send[x / 8], 4);
|
||||
hw->data_buf[(x / 32)] = word;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from SPI buffer.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param buffer_to_rcv Address to copy buffer data to.
|
||||
* @param bitlen Length to copy, in bits.
|
||||
*/
|
||||
static inline void spi_ll_read_buffer(spi_dev_t *hw, uint8_t *buffer_to_rcv, size_t bitlen)
|
||||
{
|
||||
for (int x = 0; x < bitlen; x += 32) {
|
||||
//Do a memcpy to get around possible alignment issues in rx_buffer
|
||||
uint32_t word = hw->data_buf[x / 32];
|
||||
int len = bitlen - x;
|
||||
if (len > 32) {
|
||||
len = 32;
|
||||
}
|
||||
memcpy(&buffer_to_rcv[x / 8], &word, (len + 7) / 8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether user-defined transaction is done.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return true if transaction is done, otherwise false.
|
||||
*/
|
||||
static inline bool spi_ll_usr_is_done(spi_dev_t *hw)
|
||||
{
|
||||
return hw->slave.trans_done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger start of user-defined transaction.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_user_start(spi_dev_t *hw)
|
||||
{
|
||||
hw->cmd.usr = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current running command bit-mask. (Preview)
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return Bitmask of running command, see ``SPI_CMD_REG``. 0 if no in-flight command.
|
||||
*/
|
||||
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
|
||||
{
|
||||
return hw->cmd.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the trans_done interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_disable_int(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.trans_inten = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the trans_done interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_clear_int_stat(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.trans_done = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trans_done interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_set_int_stat(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.trans_done = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the trans_done interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_enable_int(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.trans_inten = 1;
|
||||
}
|
||||
|
||||
static inline void spi_ll_slave_set_int_type(spi_dev_t *hw, spi_ll_slave_intr_type int_type)
|
||||
{
|
||||
hw->slave.trans_inten = 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: mode
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Enable/disable the postive-cs feature.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cs One of the CS (0-2) to enable/disable the feature.
|
||||
* @param pos_cs true to enable the feature, otherwise disable (default).
|
||||
*/
|
||||
static inline void spi_ll_master_set_pos_cs(spi_dev_t *hw, int cs, uint32_t pos_cs)
|
||||
{
|
||||
if (pos_cs) {
|
||||
hw->pin.master_cs_pol |= (1 << cs);
|
||||
} else {
|
||||
hw->pin.master_cs_pol &= (1 << cs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the LSBFIRST feature for TX data.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param lsbfirst true if LSB of TX data to be sent first, otherwise MSB is sent first (default).
|
||||
*/
|
||||
static inline void spi_ll_set_tx_lsbfirst(spi_dev_t *hw, bool lsbfirst)
|
||||
{
|
||||
hw->ctrl.wr_bit_order = lsbfirst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the LSBFIRST feature for RX data.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param lsbfirst true if first bit received as LSB, otherwise as MSB (default).
|
||||
*/
|
||||
static inline void spi_ll_set_rx_lsbfirst(spi_dev_t *hw, bool lsbfirst)
|
||||
{
|
||||
hw->ctrl.rd_bit_order = lsbfirst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI mode for the peripheral as master.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param mode SPI mode to work at, 0-3.
|
||||
*/
|
||||
static inline void spi_ll_master_set_mode(spi_dev_t *hw, uint8_t mode)
|
||||
{
|
||||
//Configure polarity
|
||||
if (mode == 0) {
|
||||
hw->pin.ck_idle_edge = 0;
|
||||
hw->user.ck_out_edge = 0;
|
||||
} else if (mode == 1) {
|
||||
hw->pin.ck_idle_edge = 0;
|
||||
hw->user.ck_out_edge = 1;
|
||||
} else if (mode == 2) {
|
||||
hw->pin.ck_idle_edge = 1;
|
||||
hw->user.ck_out_edge = 1;
|
||||
} else if (mode == 3) {
|
||||
hw->pin.ck_idle_edge = 1;
|
||||
hw->user.ck_out_edge = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI mode for the peripheral as slave.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param mode SPI mode to work at, 0-3.
|
||||
*/
|
||||
static inline void spi_ll_slave_set_mode(spi_dev_t *hw, const int mode, bool dma_used)
|
||||
{
|
||||
if (mode == 0) {
|
||||
//The timing needs to be fixed to meet the requirements of DMA
|
||||
hw->pin.ck_idle_edge = 1;
|
||||
hw->user.ck_i_edge = 0;
|
||||
hw->ctrl2.miso_delay_mode = 0;
|
||||
hw->ctrl2.miso_delay_num = 0;
|
||||
hw->ctrl2.mosi_delay_mode = 2;
|
||||
hw->ctrl2.mosi_delay_num = 2;
|
||||
} else if (mode == 1) {
|
||||
hw->pin.ck_idle_edge = 1;
|
||||
hw->user.ck_i_edge = 1;
|
||||
hw->ctrl2.miso_delay_mode = 2;
|
||||
hw->ctrl2.miso_delay_num = 0;
|
||||
hw->ctrl2.mosi_delay_mode = 0;
|
||||
hw->ctrl2.mosi_delay_num = 0;
|
||||
} else if (mode == 2) {
|
||||
//The timing needs to be fixed to meet the requirements of DMA
|
||||
hw->pin.ck_idle_edge = 0;
|
||||
hw->user.ck_i_edge = 1;
|
||||
hw->ctrl2.miso_delay_mode = 0;
|
||||
hw->ctrl2.miso_delay_num = 0;
|
||||
hw->ctrl2.mosi_delay_mode = 1;
|
||||
hw->ctrl2.mosi_delay_num = 2;
|
||||
} else if (mode == 3) {
|
||||
hw->pin.ck_idle_edge = 0;
|
||||
hw->user.ck_i_edge = 0;
|
||||
hw->ctrl2.miso_delay_mode = 1;
|
||||
hw->ctrl2.miso_delay_num = 0;
|
||||
hw->ctrl2.mosi_delay_mode = 0;
|
||||
hw->ctrl2.mosi_delay_num = 0;
|
||||
}
|
||||
|
||||
/* Silicon issues exists in mode 0 and 2 with DMA, change clock phase to
|
||||
* avoid dma issue. This will cause slave output to appear at most half a
|
||||
* spi clock before
|
||||
*/
|
||||
if (dma_used) {
|
||||
if (mode == 0) {
|
||||
hw->pin.ck_idle_edge = 0;
|
||||
hw->user.ck_i_edge = 1;
|
||||
hw->ctrl2.miso_delay_mode = 0;
|
||||
hw->ctrl2.miso_delay_num = 2;
|
||||
hw->ctrl2.mosi_delay_mode = 0;
|
||||
hw->ctrl2.mosi_delay_num = 3;
|
||||
} else if (mode == 2) {
|
||||
hw->pin.ck_idle_edge = 1;
|
||||
hw->user.ck_i_edge = 0;
|
||||
hw->ctrl2.miso_delay_mode = 0;
|
||||
hw->ctrl2.miso_delay_num = 2;
|
||||
hw->ctrl2.mosi_delay_mode = 0;
|
||||
hw->ctrl2.mosi_delay_num = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param half_duplex true to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_ll_set_half_duplex(spi_dev_t *hw, bool half_duplex)
|
||||
{
|
||||
hw->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in SIO mode or not.
|
||||
*
|
||||
* SIO is a mode which MOSI and MISO share a line. The device MUST work in half-duplexmode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sio_mode true to work in SIO mode, otherwise false.
|
||||
*/
|
||||
static inline void spi_ll_set_sio_mode(spi_dev_t *hw, int sio_mode)
|
||||
{
|
||||
hw->user.sio = sio_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the io mode for the master to work at.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param io_mode IO mode to work at, see ``spi_ll_io_mode_t``.
|
||||
*/
|
||||
static inline void spi_ll_master_set_io_mode(spi_dev_t *hw, spi_ll_io_mode_t io_mode)
|
||||
{
|
||||
hw->ctrl.val &= ~(SPI_FREAD_DUAL | SPI_FREAD_QUAD | SPI_FREAD_DIO | SPI_FREAD_QIO);
|
||||
hw->user.val &= ~(SPI_FWRITE_DUAL | SPI_FWRITE_QUAD | SPI_FWRITE_DIO | SPI_FWRITE_QIO);
|
||||
switch (io_mode) {
|
||||
case SPI_LL_IO_MODE_DIO:
|
||||
hw->ctrl.fread_dio = 1;
|
||||
hw->user.fwrite_dio = 1;
|
||||
break;
|
||||
case SPI_LL_IO_MODE_DUAL:
|
||||
hw->ctrl.fread_dual = 1;
|
||||
hw->user.fwrite_dual = 1;
|
||||
break;
|
||||
case SPI_LL_IO_MODE_QIO:
|
||||
hw->ctrl.fread_qio = 1;
|
||||
hw->user.fwrite_qio = 1;
|
||||
break;
|
||||
case SPI_LL_IO_MODE_QUAD:
|
||||
hw->ctrl.fread_quad = 1;
|
||||
hw->user.fwrite_quad = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
if (io_mode != SPI_LL_IO_MODE_NORMAL) {
|
||||
hw->ctrl.fastrd_mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select one of the CS to use in current transaction.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cs_id The cs to use, 0-2, otherwise none of them is used.
|
||||
*/
|
||||
static inline void spi_ll_master_select_cs(spi_dev_t *hw, int cs_id)
|
||||
{
|
||||
hw->pin.cs0_dis = (cs_id == 0) ? 0 : 1;
|
||||
hw->pin.cs1_dis = (cs_id == 1) ? 0 : 1;
|
||||
hw->pin.cs2_dis = (cs_id == 2) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: parameters
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the clock for master by stored value.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param val stored clock configuration calculated before (by ``spi_ll_cal_clock``).
|
||||
*/
|
||||
static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, spi_ll_clock_val_t *val)
|
||||
{
|
||||
hw->clock.val = *(uint32_t *)val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the frequency of given dividers. Don't use in app.
|
||||
*
|
||||
* @param fapb APB clock of the system.
|
||||
* @param pre Pre devider.
|
||||
* @param n main divider.
|
||||
*
|
||||
* @return Frequency of given dividers.
|
||||
*/
|
||||
static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n)
|
||||
{
|
||||
return (fapb / (pre * n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the nearest frequency avaliable for master.
|
||||
*
|
||||
* @param fapb APB clock of the system.
|
||||
* @param hz Frequncy desired.
|
||||
* @param duty_cycle Duty cycle desired.
|
||||
* @param out_reg Output address to store the calculated clock configurations for the return frequency.
|
||||
*
|
||||
* @return Actual (nearest) frequency.
|
||||
*/
|
||||
static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ll_clock_val_t *out_reg)
|
||||
{
|
||||
typeof(SPI1.clock) reg;
|
||||
int eff_clk;
|
||||
|
||||
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
|
||||
if (hz > ((fapb / 4) * 3)) {
|
||||
//Using Fapb directly will give us the best result here.
|
||||
reg.clkcnt_l = 0;
|
||||
reg.clkcnt_h = 0;
|
||||
reg.clkcnt_n = 0;
|
||||
reg.clkdiv_pre = 0;
|
||||
reg.clk_equ_sysclk = 1;
|
||||
eff_clk = fapb;
|
||||
} else {
|
||||
//For best duty cycle resolution, we want n to be as close to 32 as possible, but
|
||||
//we also need a pre/n combo that gets us as close as possible to the intended freq.
|
||||
//To do this, we bruteforce n and calculate the best pre to go along with that.
|
||||
//If there's a choice between pre/n combos that give the same result, use the one
|
||||
//with the higher n.
|
||||
int pre, n, h, l;
|
||||
int bestn = -1;
|
||||
int bestpre = -1;
|
||||
int besterr = 0;
|
||||
int errval;
|
||||
for (n = 2; n <= 64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse.
|
||||
//Effectively, this does pre=round((fapb/n)/hz).
|
||||
pre = ((fapb / n) + (hz / 2)) / hz;
|
||||
if (pre <= 0) {
|
||||
pre = 1;
|
||||
}
|
||||
if (pre > 8192) {
|
||||
pre = 8192;
|
||||
}
|
||||
errval = abs(spi_ll_freq_for_pre_n(fapb, pre, n) - hz);
|
||||
if (bestn == -1 || errval <= besterr) {
|
||||
besterr = errval;
|
||||
bestn = n;
|
||||
bestpre = pre;
|
||||
}
|
||||
}
|
||||
|
||||
n = bestn;
|
||||
pre = bestpre;
|
||||
l = n;
|
||||
//This effectively does round((duty_cycle*n)/256)
|
||||
h = (duty_cycle * n + 127) / 256;
|
||||
if (h <= 0) {
|
||||
h = 1;
|
||||
}
|
||||
|
||||
reg.clk_equ_sysclk = 0;
|
||||
reg.clkcnt_n = n - 1;
|
||||
reg.clkdiv_pre = pre - 1;
|
||||
reg.clkcnt_h = h - 1;
|
||||
reg.clkcnt_l = l - 1;
|
||||
eff_clk = spi_ll_freq_for_pre_n(fapb, pre, n);
|
||||
}
|
||||
if (out_reg != NULL) {
|
||||
*(uint32_t *)out_reg = reg.val;
|
||||
}
|
||||
return eff_clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and set clock for SPI master according to desired parameters.
|
||||
*
|
||||
* This takes long, suggest to calculate the configuration during
|
||||
* initialization by ``spi_ll_master_cal_clock`` and store the result, then
|
||||
* configure the clock by stored value when used by
|
||||
* ``spi_ll_msater_set_clock_by_reg``.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param fapb APB clock of the system.
|
||||
* @param hz Frequncy desired.
|
||||
* @param duty_cycle Duty cycle desired.
|
||||
*
|
||||
* @return Actual frequency that is used.
|
||||
*/
|
||||
static inline int spi_ll_master_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle)
|
||||
{
|
||||
spi_ll_clock_val_t reg_val;
|
||||
int freq = spi_ll_master_cal_clock(fapb, hz, duty_cycle, ®_val);
|
||||
spi_ll_master_set_clock_by_reg(hw, ®_val);
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the CK sel feature for a CS pin.
|
||||
*
|
||||
* CK sel is a feature to toggle the CS line along with the clock.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cs CS pin to enable/disable the feature, 0-2.
|
||||
* @param cksel true to enable the feature, otherwise false.
|
||||
*/
|
||||
static inline void spi_ll_master_set_cksel(spi_dev_t *hw, int cs, uint32_t cksel)
|
||||
{
|
||||
if (cksel) {
|
||||
hw->pin.master_ck_sel |= (1 << cs);
|
||||
} else {
|
||||
hw->pin.master_ck_sel &= (1 << cs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mosi delay after the output edge to the signal. (Preview)
|
||||
*
|
||||
* The delay mode/num is a Espressif conception, may change in the new chips.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param delay_mode Delay mode, see TRM.
|
||||
* @param delay_num APB clocks to delay.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int delay_num)
|
||||
{
|
||||
hw->ctrl2.mosi_delay_mode = delay_mode;
|
||||
hw->ctrl2.mosi_delay_num = delay_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the miso delay applied to the input signal before the internal peripheral. (Preview)
|
||||
*
|
||||
* The delay mode/num is a Espressif conception, may change in the new chips.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param delay_mode Delay mode, see TRM.
|
||||
* @param delay_num APB clocks to delay.
|
||||
*/
|
||||
static inline void spi_ll_set_miso_delay(spi_dev_t *hw, int delay_mode, int delay_num)
|
||||
{
|
||||
hw->ctrl2.miso_delay_mode = delay_mode;
|
||||
hw->ctrl2.miso_delay_num = delay_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dummy clocks to output before RX phase (master), or clocks to skip
|
||||
* before the data phase and after the address phase (slave).
|
||||
*
|
||||
* Note this phase is also used to compensate RX timing in half duplex mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_ll_set_dummy(spi_dev_t *hw, int dummy_n)
|
||||
{
|
||||
hw->user.usr_dummy = dummy_n ? 1 : 0;
|
||||
hw->user1.usr_dummy_cyclelen = dummy_n - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay of SPI clocks before the CS inactive edge after the last SPI clock.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param hold Delay of SPI clocks after the last clock, 0 to disable the hold phase.
|
||||
*/
|
||||
static inline void spi_ll_master_set_cs_hold(spi_dev_t *hw, int hold)
|
||||
{
|
||||
hw->ctrl2.hold_time = hold;
|
||||
hw->user.cs_hold = hold ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay of SPI clocks before the first SPI clock after the CS active edge.
|
||||
*
|
||||
* Note ESP32 doesn't support to use this feature when command/address phases
|
||||
* are used in full duplex mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup Delay of SPI clocks after the CS active edge, 0 to disable the setup phase.
|
||||
*/
|
||||
static inline void spi_ll_master_set_cs_setup(spi_dev_t *hw, uint8_t setup)
|
||||
{
|
||||
hw->ctrl2.setup_time = setup - 1;
|
||||
hw->user.cs_setup = setup ? 1 : 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Configs: data
|
||||
*----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Set the input length (master).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_ll_set_miso_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||
{
|
||||
hw->miso_dlen.usr_miso_dbitlen = bitlen - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the output length (master).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_ll_set_mosi_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||
{
|
||||
hw->mosi_dlen.usr_mosi_dbitlen = bitlen - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum input length (slave).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_ll_slave_set_rx_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||
{
|
||||
hw->slv_wrbuf_dlen.bit_len = bitlen - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum output length (slave).
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_ll_slave_set_tx_bitlen(spi_dev_t *hw, size_t bitlen)
|
||||
{
|
||||
hw->slv_rdbuf_dlen.bit_len = bitlen - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of command phase.
|
||||
*
|
||||
* When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit
|
||||
* command phases takes 4 cycles in 4-bit mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen Length of command phase, in bits. 0 to disable the command phase.
|
||||
*/
|
||||
static inline void spi_ll_set_command_bitlen(spi_dev_t *hw, int bitlen)
|
||||
{
|
||||
hw->user2.usr_command_bitlen = bitlen - 1;
|
||||
hw->user.usr_command = bitlen ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the length of address phase.
|
||||
*
|
||||
* When in 4-bit mode, the SPI cycles of the phase will be shorter. E.g. 16-bit
|
||||
* address phases takes 4 cycles in 4-bit mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen Length of address phase, in bits. 0 to disable the address phase.
|
||||
*/
|
||||
static inline void spi_ll_set_addr_bitlen(spi_dev_t *hw, int bitlen)
|
||||
{
|
||||
hw->user1.usr_addr_bitlen = bitlen - 1;
|
||||
hw->user.usr_addr = bitlen ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address value in an intuitive way.
|
||||
*
|
||||
* The length and lsbfirst is required to shift and swap the address to the right place.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param address Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_ll_set_address(spi_dev_t *hw, uint64_t addr, int addrlen, uint32_t lsbfirst)
|
||||
{
|
||||
if (lsbfirst) {
|
||||
/* The output address start from the LSB of the highest byte, i.e.
|
||||
* addr[24] -> addr[31]
|
||||
* ...
|
||||
* addr[0] -> addr[7]
|
||||
* slv_wr_status[24] -> slv_wr_status[31]
|
||||
* ...
|
||||
* slv_wr_status[0] -> slv_wr_status[7]
|
||||
* So swap the byte order to let the LSB sent first.
|
||||
*/
|
||||
addr = HAL_SWAP64(addr);
|
||||
hw->addr = addr >> 32;
|
||||
hw->slv_wr_status = addr;
|
||||
} else {
|
||||
// shift the address to MSB of addr (and maybe slv_wr_status) register.
|
||||
// output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register.
|
||||
if (addrlen > 32) {
|
||||
hw->addr = addr >> (addrlen - 32);
|
||||
hw->slv_wr_status = addr << (64 - addrlen);
|
||||
} else {
|
||||
hw->addr = addr << (32 - addrlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the command value in an intuitive way.
|
||||
*
|
||||
* The length and lsbfirst is required to shift and swap the command to the right place.
|
||||
*
|
||||
* @param hw Beginning command of the peripheral registers.
|
||||
* @param command Command to set
|
||||
* @param addrlen Length of the command phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
if (lsbfirst) {
|
||||
// The output command start from bit0 to bit 15, kept as is.
|
||||
hw->user2.usr_command_value = cmd;
|
||||
} else {
|
||||
/* Output command will be sent from bit 7 to 0 of command_value, and
|
||||
* then bit 15 to 8 of the same register field. Shift and swap to send
|
||||
* more straightly.
|
||||
*/
|
||||
hw->user2.usr_command_value = HAL_SPI_SWAP_DATA_TX(cmd, cmdlen);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the RX data phase.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable true if RX phase exist, otherwise false.
|
||||
*/
|
||||
static inline void spi_ll_enable_miso(spi_dev_t *hw, int enable)
|
||||
{
|
||||
hw->user.usr_miso = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable the TX data phase.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable true if TX phase exist, otherwise false.
|
||||
*/
|
||||
static inline void spi_ll_enable_mosi(spi_dev_t *hw, int enable)
|
||||
{
|
||||
hw->user.usr_mosi = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the slave peripheral before next transaction.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*/
|
||||
static inline void spi_ll_slave_reset(spi_dev_t *hw)
|
||||
{
|
||||
hw->slave.sync_reset = 1;
|
||||
hw->slave.sync_reset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the received bit length of the slave.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return Received bits of the slave.
|
||||
*/
|
||||
static inline uint32_t spi_ll_slave_get_rcv_bitlen(spi_dev_t *hw)
|
||||
{
|
||||
return hw->slv_rd_bit.slv_rdata_bit;
|
||||
}
|
||||
|
||||
|
||||
#undef SPI_LL_RST_MASK
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
399
components/hal/esp32/include/hal/timer_ll.h
Normal file
399
components/hal/esp32/include/hal/timer_ll.h
Normal file
@@ -0,0 +1,399 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for Timer Group register operations.
|
||||
// Note that most of the register operations in this layer are non-atomic operations.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "hal/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_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
|
||||
_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
|
||||
|
||||
// Get timer group instance with giving group number
|
||||
#define TIMER_LL_GET_HW(num) ((num == 0) ? (&TIMERG0) : (&TIMERG1))
|
||||
|
||||
/**
|
||||
* @brief Set timer clock prescale value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param divider Prescale value (0 and 1 are not valid)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider)
|
||||
{
|
||||
// refer to TRM 18.2.1
|
||||
if (divider == 65536) {
|
||||
divider = 0;
|
||||
} else if (divider == 1) {
|
||||
divider = 2;
|
||||
}
|
||||
int timer_en = hw->hw_timer[timer_num].config.enable;
|
||||
hw->hw_timer[timer_num].config.enable = 0;
|
||||
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 = (uint32_t) (load_val >> 32);
|
||||
hw->hw_timer[timer_num].load_low = (uint32_t) load_val;
|
||||
hw->hw_timer[timer_num].reload = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get counter value from time-base counter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param timer_val Pointer to accept the counter value
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
|
||||
{
|
||||
hw->hw_timer[timer_num].update = 1;
|
||||
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set counter mode, include increment mode and decrement mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param increase_en True to increment mode, fasle to decrement mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.increase = increase_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get counter mode, include increment mode and decrement mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Increment mode
|
||||
* - false Decrement mode
|
||||
*/
|
||||
static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.increase;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set counter status, enable or disable counter.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param counter_en True to enable counter, false to disable counter
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.enable = counter_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get counter status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Enable counter
|
||||
* - false Disable conuter
|
||||
*/
|
||||
static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set auto reload mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.autoreload = auto_reload_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get auto reload mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Enable auto reload mode
|
||||
* - false Disable auto reload mode
|
||||
*/
|
||||
FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.autoreload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the counter value to trigger the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_value Counter value to trigger the alarm
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
|
||||
{
|
||||
hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
|
||||
hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the counter value to trigger the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_value Pointer to accept the counter value to trigger the alarm
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value)
|
||||
{
|
||||
*alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the alarm status, enable or disable the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_en True to enable alarm, false to disable alarm
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.alarm_en = alarm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the alarm status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Enable alarm
|
||||
* - false Disable alarm
|
||||
*/
|
||||
static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.alarm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
hw->int_ena.val |= BIT(timer_num);
|
||||
hw->hw_timer[timer_num].config.level_int_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
hw->int_ena.val &= (~BIT(timer_num));
|
||||
hw->hw_timer[timer_num].config.level_int_en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
hw->int_clr_timers.val |= BIT(timer_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param intr_status Interrupt status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status)
|
||||
{
|
||||
*intr_status = hw->int_st_timers.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the level interrupt status, enable or disable the level interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param level_int_en True to enable level interrupt, false to disable level interrupt
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.level_int_en = level_int_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the level interrupt status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Enable level interrupt
|
||||
* - false Disable level interrupt
|
||||
*/
|
||||
static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.level_int_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the edge interrupt status, enable or disable the edge interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.edge_int_en = edge_int_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the edge interrupt status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
*
|
||||
* @return
|
||||
* - true Enable edge interrupt
|
||||
* - false Disable edge interrupt
|
||||
*/
|
||||
static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.edge_int_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get interrupt status register address.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return Interrupt status register address
|
||||
*/
|
||||
static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw)
|
||||
{
|
||||
return (uint32_t) & (hw->int_st_timers.val);
|
||||
}
|
||||
|
||||
static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return (1U << timer_num);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
135
components/hal/esp32/include/hal/touch_sensor_hal.h
Normal file
135
components/hal/esp32/include/hal/touch_sensor_hal.h
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The hal is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The HAL layer for touch sensor (esp32 specific part)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hal/touch_sensor_ll.h"
|
||||
#include "hal/touch_sensor_types.h"
|
||||
|
||||
#include_next "hal/touch_sensor_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set touch sensor measurement time.
|
||||
*
|
||||
* @param meas_time The duration of the touch sensor measurement.
|
||||
* t_meas = meas_time / (8MHz), the maximum measure time is 0xffff / 8M = 8.19 ms.
|
||||
*/
|
||||
#define touch_hal_set_meas_time(meas_time) touch_ll_set_meas_time(meas_time)
|
||||
|
||||
/**
|
||||
* Get touch sensor measurement time.
|
||||
*
|
||||
* @param meas_time Pointer to accept measurement cycle count.
|
||||
*/
|
||||
#define touch_hal_get_meas_time(meas_time) touch_ll_get_meas_time(meas_time)
|
||||
|
||||
/**
|
||||
* Set touch sensor interrupt trigger mode.
|
||||
* Interrupt can be triggered either when touch value is less than
|
||||
* threshold or when touch value is more than threshold.
|
||||
*
|
||||
* @param mode Touch sensor interrupt trigger mode.
|
||||
*/
|
||||
#define touch_hal_set_trigger_mode(mode) touch_ll_set_trigger_mode(mode)
|
||||
|
||||
/**
|
||||
* Get touch sensor interrupt trigger mode.
|
||||
* Interrupt can be triggered either when touch value is less than
|
||||
* threshold or when touch value is more than threshold.
|
||||
*
|
||||
* @param mode Touch sensor interrupt trigger mode.
|
||||
*/
|
||||
#define touch_hal_get_trigger_mode(mode) touch_ll_get_trigger_mode(mode)
|
||||
|
||||
/**
|
||||
* Set touch sensor interrupt trigger source. There are two sets of touch signals.
|
||||
* Set1 and set2 can be mapped to several touch signals. Either set will be triggered
|
||||
* if at least one of its touch signal is 'touched'. The interrupt can be configured to be generated
|
||||
* if set1 is triggered, or only if both sets are triggered.
|
||||
*
|
||||
* @param src Touch sensor interrupt trigger source.
|
||||
*/
|
||||
#define touch_hal_set_trigger_source(src) touch_ll_set_trigger_source(src)
|
||||
|
||||
/**
|
||||
* Get touch sensor interrupt trigger source.
|
||||
*
|
||||
* @param src Pointer to accept touch sensor interrupt trigger source.
|
||||
*/
|
||||
#define touch_hal_get_trigger_source(src) touch_ll_get_trigger_source(src)
|
||||
|
||||
/**
|
||||
* Set touch sensor group mask.
|
||||
* Touch pad module has two sets of signals, 'Touched' signal is triggered only if
|
||||
* at least one of touch pad in this group is "touched".
|
||||
* This function will set the register bits according to the given bitmask.
|
||||
*
|
||||
* @param set1_mask bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
#define touch_hal_set_group_mask(group1_mask, group2_mask) touch_ll_set_group_mask(group1_mask, group2_mask)
|
||||
|
||||
/**
|
||||
* Get touch sensor group mask.
|
||||
*
|
||||
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
#define touch_hal_get_group_mask(group1_mask, group2_mask) touch_ll_get_group_mask(group1_mask, group2_mask)
|
||||
|
||||
/**
|
||||
* Clear touch sensor group mask.
|
||||
*
|
||||
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
#define touch_hal_clear_group_mask(group1_mask, group2_mask) touch_ll_clear_group_mask(group1_mask, group2_mask)
|
||||
|
||||
/**
|
||||
* To enable touch pad interrupt.
|
||||
*/
|
||||
#define touch_hal_intr_enable() touch_ll_intr_enable()
|
||||
|
||||
/**
|
||||
* To disable touch pad interrupt.
|
||||
*/
|
||||
#define touch_hal_intr_disable() touch_ll_intr_disable()
|
||||
|
||||
/**
|
||||
* To clear touch pad interrupt.
|
||||
*/
|
||||
#define touch_hal_intr_clear() touch_ll_intr_clear()
|
||||
|
||||
/**
|
||||
* Get the touch pad which caused wakeup from deep sleep.
|
||||
*
|
||||
* @param pad_num pointer to touch pad which caused wakeup.
|
||||
*/
|
||||
void touch_hal_get_wakeup_status(touch_pad_t *pad_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
507
components/hal/esp32/include/hal/touch_sensor_ll.h
Normal file
507
components/hal/esp32/include/hal/touch_sensor_ll.h
Normal file
@@ -0,0 +1,507 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The Lowlevel layer for Touch Sensor
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "soc/touch_sensor_periph.h"
|
||||
#include "hal/touch_sensor_types.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//Some register bits of touch sensor 8 and 9 are mismatched, we need to swap the bits.
|
||||
#define TOUCH_LL_BIT_SWAP(data, n, m) (((data >> n) & 0x1) == ((data >> m) & 0x1) ? (data) : ((data) ^ ((0x1 <<n) | (0x1 << m))))
|
||||
#define TOUCH_LL_BITS_SWAP(v) TOUCH_LL_BIT_SWAP(v, TOUCH_PAD_NUM8, TOUCH_PAD_NUM9)
|
||||
|
||||
/**
|
||||
* Swap the number of touch8 and touch9.
|
||||
*
|
||||
* @touch_num Touch channel num.
|
||||
*/
|
||||
static inline touch_pad_t touch_ll_num_wrap(touch_pad_t touch_num)
|
||||
{
|
||||
if (touch_num == TOUCH_PAD_NUM8) {
|
||||
return TOUCH_PAD_NUM9;
|
||||
} else if (touch_num == TOUCH_PAD_NUM9) {
|
||||
return TOUCH_PAD_NUM8;
|
||||
}
|
||||
return touch_num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor measurement time.
|
||||
*
|
||||
* @param meas_time The duration of the touch sensor measurement.
|
||||
* t_meas = meas_time / (8MHz), the maximum measure time is 0xffff / 8M = 8.19 ms.
|
||||
*/
|
||||
static inline void touch_ll_set_meas_time(uint16_t meas_time)
|
||||
{
|
||||
//touch sensor measure time= meas_cycle / 8Mhz
|
||||
SENS.sar_touch_ctrl1.touch_meas_delay = meas_time;
|
||||
//the waiting cycles (in 8MHz) between TOUCH_START and TOUCH_XPD
|
||||
SENS.sar_touch_ctrl1.touch_xpd_wait = SOC_TOUCH_PAD_MEASURE_WAIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor measurement time.
|
||||
*
|
||||
* @param meas_time Pointer to accept measurement cycle count.
|
||||
*/
|
||||
static inline void touch_ll_get_meas_time(uint16_t *meas_time)
|
||||
{
|
||||
*meas_time = SENS.sar_touch_ctrl1.touch_meas_delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor sleep time (interval of measurement).
|
||||
*
|
||||
* @param sleep_time The touch sensor will sleep after each measurement.
|
||||
* sleep_cycle decide the interval between each measurement.
|
||||
* t_sleep = sleep_cycle / (RTC_SLOW_CLK frequency).
|
||||
* The approximate frequency value of RTC_SLOW_CLK can be obtained using `rtc_clk_slow_freq_get_hz` function.
|
||||
*/
|
||||
static inline void touch_ll_set_sleep_time(uint16_t sleep_time)
|
||||
{
|
||||
//touch sensor sleep cycle Time = sleep_cycle / RTC_SLOW_CLK( can be 150k or 32k depending on the options)
|
||||
SENS.sar_touch_ctrl2.touch_sleep_cycles = sleep_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor sleep time.
|
||||
*
|
||||
* @param sleep_time Pointer to accept sleep cycle count.
|
||||
*/
|
||||
static inline void touch_ll_get_sleep_time(uint16_t *sleep_time)
|
||||
{
|
||||
*sleep_time = SENS.sar_touch_ctrl1.touch_meas_delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor high voltage threshold of chanrge.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
* So the high threshold should be less than the supply voltage.
|
||||
*
|
||||
* @param refh The high voltage threshold of chanrge.
|
||||
*/
|
||||
static inline void touch_ll_set_voltage_high(touch_high_volt_t refh)
|
||||
{
|
||||
RTCIO.touch_cfg.drefh = refh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor high voltage threshold of chanrge.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
* So the high threshold should be less than the supply voltage.
|
||||
*
|
||||
* @param refh The high voltage threshold of chanrge.
|
||||
*/
|
||||
static inline void touch_ll_get_voltage_high(touch_high_volt_t *refh)
|
||||
{
|
||||
*refh = (touch_high_volt_t)RTCIO.touch_cfg.drefh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor low voltage threshold of discharge.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
*
|
||||
* @param refl The low voltage threshold of discharge.
|
||||
*/
|
||||
static inline void touch_ll_set_voltage_low(touch_low_volt_t refl)
|
||||
{
|
||||
RTCIO.touch_cfg.drefl = refl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor low voltage threshold of discharge.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
*
|
||||
* @param refl The low voltage threshold of discharge.
|
||||
*/
|
||||
static inline void touch_ll_get_voltage_low(touch_low_volt_t *refl)
|
||||
{
|
||||
*refl = (touch_low_volt_t)RTCIO.touch_cfg.drefl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor high voltage attenuation of chanrge. The actual charge threshold is high voltage threshold minus attenuation value.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
* So the high threshold should be less than the supply voltage.
|
||||
*
|
||||
* @param refh The high voltage threshold of chanrge.
|
||||
*/
|
||||
static inline void touch_ll_set_voltage_attenuation(touch_volt_atten_t atten)
|
||||
{
|
||||
RTCIO.touch_cfg.drange = atten;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor high voltage attenuation of chanrge. The actual charge threshold is high voltage threshold minus attenuation value.
|
||||
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
|
||||
* So the high threshold should be less than the supply voltage.
|
||||
*
|
||||
* @param refh The high voltage threshold of chanrge.
|
||||
*/
|
||||
static inline void touch_ll_get_voltage_attenuation(touch_volt_atten_t *atten)
|
||||
{
|
||||
*atten = (touch_volt_atten_t)RTCIO.touch_cfg.drange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor charge/discharge speed(currents) for each pad.
|
||||
* If the slope is 0, the counter would always be zero.
|
||||
* If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.
|
||||
* If the slope is set 7, which is the maximum value, the charging and discharging would be fast.
|
||||
* The measurement time becomes shorter.
|
||||
*
|
||||
* @note The higher the charge and discharge current, the greater the immunity of the touch channel,
|
||||
* but it will increase the system power consumption.
|
||||
* @param touch_num Touch pad index.
|
||||
* @param slope touch pad charge/discharge speed(currents).
|
||||
*/
|
||||
static inline void touch_ll_set_slope(touch_pad_t touch_num, touch_cnt_slope_t slope)
|
||||
{
|
||||
RTCIO.touch_pad[touch_num].dac = slope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor charge/discharge speed(currents) for each pad.
|
||||
* If the slope is 0, the counter would always be zero.
|
||||
* If the slope is 1, the charging and discharging would be slow. The measurement time becomes longer.
|
||||
* If the slope is set 7, which is the maximum value, the charging and discharging would be fast.
|
||||
* The measurement time becomes shorter.
|
||||
*
|
||||
* @param touch_num Touch pad index.
|
||||
* @param slope touch pad charge/discharge speed(currents).
|
||||
*/
|
||||
static inline void touch_ll_get_slope(touch_pad_t touch_num, touch_cnt_slope_t *slope)
|
||||
{
|
||||
*slope = (touch_cnt_slope_t)RTCIO.touch_pad[touch_num].dac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set initial voltage state of touch channel for each measurement.
|
||||
*
|
||||
* @param touch_num Touch pad index.
|
||||
* @param opt Initial voltage state.
|
||||
*/
|
||||
static inline void touch_ll_set_tie_option(touch_pad_t touch_num, touch_tie_opt_t opt)
|
||||
{
|
||||
touch_pad_t touch_pad_wrap = touch_ll_num_wrap(touch_num);
|
||||
RTCIO.touch_pad[touch_pad_wrap].tie_opt = opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get initial voltage state of touch channel for each measurement.
|
||||
*
|
||||
* @param touch_num Touch pad index.
|
||||
* @param opt Initial voltage state.
|
||||
*/
|
||||
static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_t *opt)
|
||||
{
|
||||
touch_pad_t touch_pad_wrap = touch_ll_num_wrap(touch_num);
|
||||
*opt = (touch_tie_opt_t)RTCIO.touch_pad[touch_pad_wrap].tie_opt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor FSM mode.
|
||||
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
|
||||
*
|
||||
* @param mode FSM mode.
|
||||
*/
|
||||
static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode)
|
||||
{
|
||||
SENS.sar_touch_ctrl2.touch_start_en = 0;
|
||||
SENS.sar_touch_ctrl2.touch_start_force = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor FSM mode.
|
||||
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
|
||||
*
|
||||
* @param mode FSM mode.
|
||||
*/
|
||||
static inline void touch_ll_get_fsm_mode(touch_fsm_mode_t *mode)
|
||||
{
|
||||
*mode = (touch_fsm_mode_t)SENS.sar_touch_ctrl2.touch_start_force;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start touch sensor FSM timer.
|
||||
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
|
||||
*
|
||||
* @param mode FSM mode.
|
||||
*/
|
||||
static inline void touch_ll_start_fsm(void)
|
||||
{
|
||||
RTCCNTL.state0.touch_slp_timer_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop touch sensor FSM timer.
|
||||
* The measurement action can be triggered by the hardware timer, as well as by the software instruction.
|
||||
*
|
||||
* @param mode FSM mode.
|
||||
*/
|
||||
static inline void touch_ll_stop_fsm(void)
|
||||
{
|
||||
RTCCNTL.state0.touch_slp_timer_en = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a touch sensor measurement, only support in SW mode of FSM.
|
||||
*/
|
||||
static inline void touch_ll_start_sw_meas(void)
|
||||
{
|
||||
SENS.sar_touch_ctrl2.touch_start_en = 0;
|
||||
SENS.sar_touch_ctrl2.touch_start_en = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor interrupt threshold.
|
||||
*
|
||||
* @note Refer to `touch_pad_set_trigger_mode` to see how to set trigger mode.
|
||||
* @param touch_num touch pad index.
|
||||
* @param threshold threshold of touchpad count.
|
||||
*/
|
||||
static inline void touch_ll_set_threshold(touch_pad_t touch_num, uint16_t threshold)
|
||||
{
|
||||
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
|
||||
if (tp_wrap & 0x1) {
|
||||
SENS.touch_thresh[tp_wrap / 2].l_thresh = threshold;
|
||||
} else {
|
||||
SENS.touch_thresh[tp_wrap / 2].h_thresh = threshold;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor interrupt threshold.
|
||||
*
|
||||
* @param touch_num touch pad index.
|
||||
* @param threshold pointer to accept threshold.
|
||||
*/
|
||||
static inline void touch_ll_get_threshold(touch_pad_t touch_num, uint16_t *threshold)
|
||||
{
|
||||
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
|
||||
if (threshold) {
|
||||
*threshold = (tp_wrap & 0x1 ) ?
|
||||
SENS.touch_thresh[tp_wrap / 2].l_thresh :
|
||||
SENS.touch_thresh[tp_wrap / 2].h_thresh;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor interrupt trigger mode.
|
||||
* Interrupt can be triggered either when touch value is less than
|
||||
* threshold or when touch value is more than threshold.
|
||||
*
|
||||
* @param mode Touch sensor interrupt trigger mode.
|
||||
*/
|
||||
static inline void touch_ll_set_trigger_mode(touch_trigger_mode_t mode)
|
||||
{
|
||||
SENS.sar_touch_ctrl1.touch_out_sel = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor interrupt trigger mode.
|
||||
* Interrupt can be triggered either when touch value is less than
|
||||
* threshold or when touch value is more than threshold.
|
||||
*
|
||||
* @param mode Touch sensor interrupt trigger mode.
|
||||
*/
|
||||
static inline void touch_ll_get_trigger_mode(touch_trigger_mode_t *mode)
|
||||
{
|
||||
*mode = (touch_trigger_mode_t)SENS.sar_touch_ctrl1.touch_out_sel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor interrupt trigger source. There are two sets of touch signals.
|
||||
* Set1 and set2 can be mapped to several touch signals. Either set will be triggered
|
||||
* if at least one of its touch signal is 'touched'. The interrupt can be configured to be generated
|
||||
* if set1 is triggered, or only if both sets are triggered.
|
||||
*
|
||||
* @param src Touch sensor interrupt trigger source.
|
||||
*/
|
||||
static inline void touch_ll_set_trigger_source(touch_trigger_src_t src)
|
||||
{
|
||||
SENS.sar_touch_ctrl1.touch_out_1en = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor interrupt trigger source.
|
||||
*
|
||||
* @param src Pointer to accept touch sensor interrupt trigger source.
|
||||
*/
|
||||
static inline void touch_ll_get_trigger_source(touch_trigger_src_t *src)
|
||||
{
|
||||
*src = (touch_trigger_src_t)SENS.sar_touch_ctrl1.touch_out_1en;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable touch sensor channel. Register touch channel into touch sensor measurement group.
|
||||
* The working mode of the touch sensor is simultaneous measurement.
|
||||
* This function will set the measure bits according to the given bitmask.
|
||||
*
|
||||
* @note If set this mask, the FSM timer should be stop firsty.
|
||||
* @note The touch sensor that in scan map, should be deinit GPIO function firstly.
|
||||
* @param enable_mask bitmask of touch sensor scan group.
|
||||
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
static inline void touch_ll_set_channel_mask(uint16_t enable_mask)
|
||||
{
|
||||
SENS.sar_touch_enable.touch_pad_worken |= TOUCH_LL_BITS_SWAP(enable_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor channel mask.
|
||||
*
|
||||
* @param enable_mask bitmask of touch sensor scan group.
|
||||
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
|
||||
*/
|
||||
static inline void touch_ll_get_channel_mask(uint16_t *enable_mask)
|
||||
{
|
||||
*enable_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_worken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable touch sensor channel by bitmask.
|
||||
*
|
||||
* @param enable_mask bitmask of touch sensor scan group.
|
||||
* e.g. TOUCH_PAD_NUM1 -> BIT(1)
|
||||
*/
|
||||
static inline void touch_ll_clear_channel_mask(uint16_t disable_mask)
|
||||
{
|
||||
SENS.sar_touch_enable.touch_pad_worken &= TOUCH_LL_BITS_SWAP(~disable_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set touch sensor group mask.
|
||||
* Touch pad module has two sets of signals, 'Touched' signal is triggered only if
|
||||
* at least one of touch pad in this group is "touched".
|
||||
* This function will set the register bits according to the given bitmask.
|
||||
*
|
||||
* @param set1_mask bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
static inline void touch_ll_set_group_mask(uint16_t group1_mask, uint16_t group2_mask)
|
||||
{
|
||||
SENS.sar_touch_enable.touch_pad_outen1 |= TOUCH_LL_BITS_SWAP(group1_mask);
|
||||
SENS.sar_touch_enable.touch_pad_outen2 |= TOUCH_LL_BITS_SWAP(group2_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor group mask.
|
||||
*
|
||||
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
static inline void touch_ll_get_group_mask(uint16_t *group1_mask, uint16_t *group2_mask)
|
||||
{
|
||||
*group1_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_outen1);
|
||||
*group2_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_enable.touch_pad_outen2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear touch sensor group mask.
|
||||
*
|
||||
* @param set1_mask pointer to accept bitmask of touch sensor signal group1, it's a 10-bit value
|
||||
* @param set2_mask pointer to accept bitmask of touch sensor signal group2, it's a 10-bit value
|
||||
*/
|
||||
static inline void touch_ll_clear_group_mask(uint16_t group1_mask, uint16_t group2_mask)
|
||||
{
|
||||
SENS.sar_touch_enable.touch_pad_outen1 &= TOUCH_LL_BITS_SWAP(~group1_mask);
|
||||
SENS.sar_touch_enable.touch_pad_outen2 &= TOUCH_LL_BITS_SWAP(~group2_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the touch sensor status, usually used in ISR to decide which pads are 'touched'.
|
||||
*
|
||||
* @param status_mask The touch sensor status. e.g. Touch1 trigger status is `status_mask & (BIT1)`.
|
||||
*/
|
||||
static inline void touch_ll_read_trigger_status_mask(uint32_t *status_mask)
|
||||
{
|
||||
*status_mask = TOUCH_LL_BITS_SWAP(SENS.sar_touch_ctrl2.touch_meas_en);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all touch sensor status.
|
||||
*/
|
||||
static inline void touch_ll_clear_trigger_status_mask(void)
|
||||
{
|
||||
SENS.sar_touch_ctrl2.touch_meas_en_clr = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* To enable touch pad interrupt.
|
||||
*/
|
||||
static inline void touch_ll_intr_enable(void)
|
||||
{
|
||||
RTCCNTL.int_ena.rtc_touch = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* To disable touch pad interrupt.
|
||||
*/
|
||||
static inline void touch_ll_intr_disable(void)
|
||||
{
|
||||
RTCCNTL.int_ena.rtc_touch = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* To clear touch pad interrupt.
|
||||
*/
|
||||
static inline void touch_ll_intr_clear(void)
|
||||
{
|
||||
RTCCNTL.int_clr.rtc_touch = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor raw data (touch sensor counter value) from register. No block.
|
||||
*
|
||||
* @param touch_num touch pad index.
|
||||
* @return touch_value pointer to accept touch sensor value.
|
||||
*/
|
||||
static inline uint32_t touch_ll_read_raw_data(touch_pad_t touch_num)
|
||||
{
|
||||
touch_pad_t tp_wrap = touch_ll_num_wrap(touch_num);
|
||||
return ((tp_wrap & 0x1) ? SENS.touch_meas[tp_wrap / 2].l_val : SENS.touch_meas[tp_wrap / 2].h_val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get touch sensor measure status. No block.
|
||||
*
|
||||
* @return
|
||||
* - If touch sensors measure done.
|
||||
*/
|
||||
static inline bool touch_ll_meas_is_done(void)
|
||||
{
|
||||
return (bool)SENS.sar_touch_ctrl2.touch_meas_done;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
706
components/hal/esp32/include/hal/twai_ll.h
Normal file
706
components/hal/esp32/include/hal/twai_ll.h
Normal file
@@ -0,0 +1,706 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in soc/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The Lowlevel layer for TWAI
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "hal/twai_types.h"
|
||||
#include "soc/twai_periph.h"
|
||||
|
||||
/* ------------------------- Defines and Typedefs --------------------------- */
|
||||
|
||||
#define TWAI_LL_STATUS_RBS (0x1 << 0)
|
||||
#define TWAI_LL_STATUS_DOS (0x1 << 1)
|
||||
#define TWAI_LL_STATUS_TBS (0x1 << 2)
|
||||
#define TWAI_LL_STATUS_TCS (0x1 << 3)
|
||||
#define TWAI_LL_STATUS_RS (0x1 << 4)
|
||||
#define TWAI_LL_STATUS_TS (0x1 << 5)
|
||||
#define TWAI_LL_STATUS_ES (0x1 << 6)
|
||||
#define TWAI_LL_STATUS_BS (0x1 << 7)
|
||||
|
||||
#define TWAI_LL_INTR_RI (0x1 << 0)
|
||||
#define TWAI_LL_INTR_TI (0x1 << 1)
|
||||
#define TWAI_LL_INTR_EI (0x1 << 2)
|
||||
//Data overrun interrupt not supported in SW due to HW peculiarities
|
||||
#define TWAI_LL_INTR_EPI (0x1 << 5)
|
||||
#define TWAI_LL_INTR_ALI (0x1 << 6)
|
||||
#define TWAI_LL_INTR_BEI (0x1 << 7)
|
||||
|
||||
/*
|
||||
* 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
|
||||
* @return true if reset mode was entered successfully
|
||||
*
|
||||
* @note Reset mode is automatically entered on BUS OFF condition
|
||||
*/
|
||||
static inline bool twai_ll_enter_reset_mode(twai_dev_t *hw)
|
||||
{
|
||||
hw->mode_reg.rm = 1;
|
||||
return hw->mode_reg.rm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @return true if reset mode was exit successfully
|
||||
*
|
||||
* @note Reset mode must be exit to initiate BUS OFF recovery
|
||||
*/
|
||||
static inline bool twai_ll_exit_reset_mode(twai_dev_t *hw)
|
||||
{
|
||||
hw->mode_reg.rm = 0;
|
||||
return !(hw->mode_reg.rm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if in reset mode
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @return true if in reset mode
|
||||
*/
|
||||
static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw)
|
||||
{
|
||||
return hw->mode_reg.rm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set operating mode of TWAI controller
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @param mode Operating mode
|
||||
*
|
||||
* @note Must be called in reset mode
|
||||
*/
|
||||
static inline void twai_ll_set_mode(twai_dev_t *hw, twai_mode_t mode)
|
||||
{
|
||||
if (mode == TWAI_MODE_NORMAL) { //Normal Operating mode
|
||||
hw->mode_reg.lom = 0;
|
||||
hw->mode_reg.stm = 0;
|
||||
} else if (mode == TWAI_MODE_NO_ACK) { //Self Test Mode (No Ack)
|
||||
hw->mode_reg.lom = 0;
|
||||
hw->mode_reg.stm = 1;
|
||||
} else if (mode == TWAI_MODE_LISTEN_ONLY) { //Listen Only Mode
|
||||
hw->mode_reg.lom = 1;
|
||||
hw->mode_reg.stm = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------- Command Register ----------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Set TX command
|
||||
*
|
||||
* Setting the TX command will cause the TWAI controller to attempt to transmit
|
||||
* the frame stored in the TX buffer. The TX buffer will be occupied (i.e.,
|
||||
* locked) until TX completes.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Transmit commands should be called last (i.e., after handling buffer
|
||||
* release and clear data overrun) in order to prevent the other commands
|
||||
* overwriting this latched TX bit with 0.
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.tr = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set single shot TX command
|
||||
*
|
||||
* Similar to setting TX command, but the TWAI controller will not automatically
|
||||
* retry transmission upon an error (e.g., due to an acknowledgement error).
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Transmit commands should be called last (i.e., after handling buffer
|
||||
* release and clear data overrun) in order to prevent the other commands
|
||||
* overwriting this latched TX bit with 0.
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.val = 0x03; //Writing to TR and AT simultaneously
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aborts TX
|
||||
*
|
||||
* Frames awaiting TX will be aborted. Frames already being TX are not aborted.
|
||||
* Transmission Complete Status bit is automatically set to 1.
|
||||
* Similar to setting TX command, but the TWAI controller will not automatically
|
||||
* retry transmission upon an error (e.g., due to acknowledge error).
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Transmit commands should be called last (i.e., after handling buffer
|
||||
* release and clear data overrun) in order to prevent the other commands
|
||||
* overwriting this latched TX bit with 0.
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.at = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release RX buffer
|
||||
*
|
||||
* Rotates RX buffer to the next frame in the RX FIFO.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.rrb = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear data overrun
|
||||
*
|
||||
* Clears the data overrun status bit
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.cdo = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set self reception single shot command
|
||||
*
|
||||
* Similar to setting TX command, but the TWAI controller also simultaneously
|
||||
* receive the transmitted frame and is generally used for self testing
|
||||
* purposes. The TWAI controller will not ACK the received message, so consider
|
||||
* using the NO_ACK operating mode.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Transmit commands should be called last (i.e., after handling buffer
|
||||
* release and clear data overrun) in order to prevent the other commands
|
||||
* overwriting this latched TX bit with 0.
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.srr = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set self reception request command
|
||||
*
|
||||
* Similar to setting the self reception request, but the TWAI controller will
|
||||
* not automatically retry transmission upon an error (e.g., due to and
|
||||
* acknowledgement error).
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Transmit commands should be called last (i.e., after handling buffer
|
||||
* release and clear data overrun) in order to prevent the other commands
|
||||
* overwriting this latched TX bit with 0.
|
||||
*/
|
||||
static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
|
||||
{
|
||||
hw->command_reg.val = 0x12;
|
||||
}
|
||||
|
||||
/* --------------------------- Status Register ------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Get all status bits
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @return Status bits
|
||||
*/
|
||||
static inline uint32_t twai_ll_get_status(twai_dev_t *hw)
|
||||
{
|
||||
return hw->status_reg.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if RX FIFO overrun status bit is set
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @return Overrun status bit
|
||||
*/
|
||||
static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw)
|
||||
{
|
||||
return hw->status_reg.dos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if previously TX was successful
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @return Whether previous TX was successful
|
||||
*/
|
||||
static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
|
||||
{
|
||||
return hw->status_reg.tcs;
|
||||
}
|
||||
|
||||
//Todo: Add stand alone status bit check functions when necessary
|
||||
|
||||
/* -------------------------- Interrupt Register ---------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Get currently set interrupts
|
||||
*
|
||||
* Reading the interrupt registers will automatically clear all interrupts
|
||||
* except for the Receive Interrupt.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @return Bit mask of set interrupts
|
||||
*/
|
||||
static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
|
||||
{
|
||||
return hw->interrupt_reg.val;
|
||||
}
|
||||
|
||||
/* ----------------------- Interrupt Enable Register ------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Set which interrupts are enabled
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @param Bit mask of interrupts to enable
|
||||
*
|
||||
* @note Must be called in reset mode
|
||||
*/
|
||||
static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
|
||||
{
|
||||
#if (CONFIG_ESP32_REV_MIN >= 2)
|
||||
//ESP32 Rev 2 or later has brp div field. Need to mask it out
|
||||
hw->interrupt_enable_reg.val = (hw->interrupt_enable_reg.val & 0x10) | intr_mask;
|
||||
#else
|
||||
hw->interrupt_enable_reg.val = intr_mask;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------ Bus Timing Registers --------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Set bus timing
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @param brp Baud Rate Prescaler
|
||||
* @param sjw Synchronization Jump Width
|
||||
* @param tseg1 Timing Segment 1
|
||||
* @param tseg2 Timing Segment 2
|
||||
* @param triple_sampling Triple Sampling enable/disable
|
||||
*
|
||||
* @note Must be called in reset mode
|
||||
* @note ESP32 rev 2 or later can support a x2 brp by setting a brp_div bit,
|
||||
* allowing the brp to go from a maximum of 128 to 256.
|
||||
*/
|
||||
static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling)
|
||||
{
|
||||
#if (CONFIG_ESP32_REV_MIN >= 2)
|
||||
if (brp > TWAI_BRP_DIV_THRESH) {
|
||||
//Need to set brp_div bit
|
||||
hw->interrupt_enable_reg.brp_div = 1;
|
||||
brp /= 2;
|
||||
} else {
|
||||
hw->interrupt_enable_reg.brp_div = 0;
|
||||
}
|
||||
#endif
|
||||
hw->bus_timing_0_reg.brp = (brp / 2) - 1;
|
||||
hw->bus_timing_0_reg.sjw = sjw - 1;
|
||||
hw->bus_timing_1_reg.tseg1 = tseg1 - 1;
|
||||
hw->bus_timing_1_reg.tseg2 = tseg2 - 1;
|
||||
hw->bus_timing_1_reg.sam = triple_sampling;
|
||||
}
|
||||
|
||||
/* ----------------------------- ALC Register ------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Clear Arbitration Lost Capture Register
|
||||
*
|
||||
* Reading the ALC register rearms the Arbitration Lost Interrupt
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*/
|
||||
static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
|
||||
{
|
||||
(void)hw->arbitration_lost_captue_reg.val;
|
||||
//Todo: Decode ALC register
|
||||
}
|
||||
|
||||
/* ----------------------------- 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;
|
||||
//Todo: Decode error code capture
|
||||
}
|
||||
|
||||
/* ----------------------------- 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 RTR)
|
||||
for (int i = 0; (i < dlc) && (i < TWAI_FRAME_MAX_DLC); i++) {
|
||||
data_buffer[i] = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse formatted TWAI frame (RX Buffer Layout) into its constituent contents
|
||||
*
|
||||
* @param[in] rx_frame Pointer to formatted frame
|
||||
* @param[out] id 11 or 29bit ID
|
||||
* @param[out] dlc Data length code
|
||||
* @param[out] data Data. Left over bytes set to 0.
|
||||
* @param[out] format Type of TWAI frame
|
||||
*/
|
||||
static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
|
||||
uint8_t *data, uint32_t *flags)
|
||||
{
|
||||
//Copy frame information
|
||||
*dlc = rx_frame->dlc;
|
||||
uint32_t flags_temp = 0;
|
||||
flags_temp |= (rx_frame->frame_format) ? TWAI_MSG_FLAG_EXTD : 0;
|
||||
flags_temp |= (rx_frame->rtr) ? TWAI_MSG_FLAG_RTR : 0;
|
||||
flags_temp |= (rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_MSG_FLAG_DLC_NON_COMP : 0;
|
||||
*flags = flags_temp;
|
||||
|
||||
//Copy ID. The ID registers are big endian and left aligned, therefore a bswap will be required
|
||||
if (rx_frame->frame_format) {
|
||||
uint32_t id_temp = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
id_temp |= rx_frame->extended.id[i] << (8 * i);
|
||||
}
|
||||
id_temp = __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 14. Set the divider to 0 to disable CLKOUT.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
* @param divider Divider for CLKOUT. Set to 0 to disable CLKOUT
|
||||
*/
|
||||
static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider)
|
||||
{
|
||||
if (divider >= 2 && divider <= 14) {
|
||||
hw->clock_divider_reg.co = 0;
|
||||
hw->clock_divider_reg.cd = (divider / 2) - 1;
|
||||
} else if (divider == 1) {
|
||||
//Setting the divider reg to max value (7) means a divider of 1
|
||||
hw->clock_divider_reg.co = 0;
|
||||
hw->clock_divider_reg.cd = 7;
|
||||
} else {
|
||||
hw->clock_divider_reg.co = 1;
|
||||
hw->clock_divider_reg.cd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set register address mapping to extended mode
|
||||
*
|
||||
* Extended mode register address mapping consists of more registers and extra
|
||||
* features.
|
||||
*
|
||||
* @param hw Start address of the TWAI registers
|
||||
*
|
||||
* @note Must be called before setting any configuration
|
||||
* @note Must be called in reset mode
|
||||
*/
|
||||
static inline void twai_ll_enable_extended_reg_layout(twai_dev_t *hw)
|
||||
{
|
||||
hw->clock_divider_reg.cm = 1;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
872
components/hal/esp32/include/hal/uart_ll.h
Normal file
872
components/hal/esp32/include/hal/uart_ll.h
Normal file
@@ -0,0 +1,872 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for 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 (UART_FIFO_LEN)
|
||||
// Get UART hardware instance with giving uart num
|
||||
#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (((num) == 1) ? (&UART1) : (&UART2)))
|
||||
|
||||
// The timeout calibration factor when using ref_tick
|
||||
#define UART_LL_TOUT_REF_FACTOR_DEFAULT (8)
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure the baud-rate.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param baud The baud-rate to be set. When the source clock is APB, the max baud-rate is `UART_LL_BITRATE_MAX`
|
||||
* @param source_clk The UART source clock. The source clock can be APB clock or REF_TICK.
|
||||
* If the source clock is REF_TICK, the UART can still work when the APB changes.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void uart_ll_set_baudrate(uart_dev_t *hw, uart_sclk_t source_clk, uint32_t baud)
|
||||
{
|
||||
uint32_t sclk_freq = (source_clk == UART_SCLK_APB) ? APB_CLK_FREQ : REF_CLK_FREQ;
|
||||
uint32_t clk_div = ((sclk_freq) << 4) / baud;
|
||||
// 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;
|
||||
// Configure the UART source clock.
|
||||
hw->conf0.tick_ref_always_on = (source_clk == UART_SCLK_APB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 src_clk = hw->conf0.tick_ref_always_on ? APB_CLK_FREQ : REF_CLK_FREQ;
|
||||
typeof(hw->clk_div) div_reg = hw->clk_div;
|
||||
return ((src_clk << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 enabled 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)
|
||||
{
|
||||
//Get the UART APB fifo addr. Read fifo, we use APB address
|
||||
uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_REG(0) : (hw == &UART1) ? UART_FIFO_REG(1) : UART_FIFO_REG(2);
|
||||
for(int i = 0; i < rd_len; i++) {
|
||||
buf[i] = READ_PERI_REG(fifo_addr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
//Get the UART AHB fifo addr, Write fifo, we use AHB address
|
||||
uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : (hw == &UART1) ? UART_FIFO_AHB_REG(1) : UART_FIFO_AHB_REG(2);
|
||||
for(int i = 0; i < wr_len; i++) {
|
||||
WRITE_PERI_REG(fifo_addr, 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)
|
||||
{
|
||||
//Hardware issue: we can not use `rxfifo_rst` to reset the hw rxfifo.
|
||||
uint16_t fifo_cnt;
|
||||
typeof(hw->mem_rx_status) rxmem_sta;
|
||||
//Get the UART APB fifo addr
|
||||
uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_REG(0) : (hw == &UART1) ? UART_FIFO_REG(1) : UART_FIFO_REG(2);
|
||||
do {
|
||||
fifo_cnt = hw->status.rxfifo_cnt;
|
||||
rxmem_sta.val = hw->mem_rx_status.val;
|
||||
if(fifo_cnt != 0 || (rxmem_sta.rd_addr != rxmem_sta.wr_addr)) {
|
||||
READ_PERI_REG(fifo_addr);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset the UART hw txfifo.
|
||||
*
|
||||
* Note: Due to hardware issue, reset UART1's txfifo will also reset UART2's txfifo.
|
||||
* So reserve this function for UART1 and UART2. Please do DPORT reset for UART and its memory at chip startup
|
||||
* to ensure the TX FIFO is reset correctly at the beginning.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void uart_ll_txfifo_rst(uart_dev_t *hw)
|
||||
{
|
||||
if (hw == &UART0) {
|
||||
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)
|
||||
{
|
||||
uint32_t fifo_cnt = hw->status.rxfifo_cnt;
|
||||
typeof(hw->mem_rx_status) rx_status = hw->mem_rx_status;
|
||||
uint32_t len = 0;
|
||||
|
||||
// When using DPort to read fifo, fifo_cnt is not credible, we need to calculate the real cnt based on the fifo read and write pointer.
|
||||
// When using AHB to read FIFO, we can use fifo_cnt to indicate the data length in fifo.
|
||||
if (rx_status.wr_addr > rx_status.rd_addr) {
|
||||
len = rx_status.wr_addr - rx_status.rd_addr;
|
||||
} else if (rx_status.wr_addr < rx_status.rd_addr) {
|
||||
len = (rx_status.wr_addr + 128) - rx_status.rd_addr;
|
||||
} else {
|
||||
len = fifo_cnt > 0 ? 128 : 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
//workaround for hardware issue, when UART stop bit set as 2-bit mode.
|
||||
if(stop_bit == UART_STOP_BITS_2) {
|
||||
hw->rs485_conf.dl1_en = 1;
|
||||
hw->conf0.stop_bit_num = 0x1;
|
||||
} else {
|
||||
hw->rs485_conf.dl1_en = 0;
|
||||
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)
|
||||
{
|
||||
//workaround for hardware issue, when UART stop bit set as 2-bit mode.
|
||||
if(hw->rs485_conf.dl1_en == 1 && hw->conf0.stop_bit_num == 0x1) {
|
||||
*stop_bit = UART_STOP_BITS_2;
|
||||
} else {
|
||||
*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->idle_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->conf1.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_conf.xon_threshold = flow_ctrl->xon_thrd;
|
||||
hw->swfc_conf.xoff_threshold = flow_ctrl->xoff_thrd;
|
||||
hw->swfc_conf.xon_char = flow_ctrl->xon_char;
|
||||
hw->swfc_conf.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 Get the UART source clock.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param source_clk The pointer to accept the UART source clock configuration.
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
static inline void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t* source_clk)
|
||||
{
|
||||
*source_clk = hw->conf0.tick_ref_always_on ? UART_SCLK_APB : UART_SCLK_REF_TICK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 - SOC_UART_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.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;
|
||||
// Must be set to 0 to automatically remove echo
|
||||
hw->rs485_conf.tx_rx_en = 0;
|
||||
// This is to void collision
|
||||
hw->rs485_conf.rx_busy_tx_en = 1;
|
||||
hw->conf0.irda_en = 0;
|
||||
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;
|
||||
// Transmitters output signal loop back to the receivers input signal
|
||||
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->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 + SOC_UART_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)
|
||||
{
|
||||
typeof(hw->status) status = hw->status;
|
||||
return ((status.txfifo_cnt == 0) && (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_thr The timeout value as a bit time. The rx timeout function will be disabled if `tout_thr == 0`.
|
||||
*
|
||||
* @return None.
|
||||
*/
|
||||
static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thr)
|
||||
{
|
||||
if (hw->conf0.tick_ref_always_on == 0) {
|
||||
//Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times.
|
||||
//T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH)
|
||||
tout_thr = tout_thr * UART_LL_TOUT_REF_FACTOR_DEFAULT;
|
||||
} else {
|
||||
//If APB_CLK is used: counting rate is BAUD tick rate / 8
|
||||
tout_thr = (tout_thr + 7) / 8;
|
||||
}
|
||||
if (tout_thr > 0) {
|
||||
hw->conf1.rx_tout_thrhd = tout_thr;
|
||||
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) {
|
||||
if (hw->conf0.tick_ref_always_on == 0) {
|
||||
tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd / UART_LL_TOUT_REF_FACTOR_DEFAULT);
|
||||
} else {
|
||||
tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd << 3);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
uint16_t tout_thrd = 0;
|
||||
if (hw->conf0.tick_ref_always_on == 0) {
|
||||
tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V / UART_LL_TOUT_REF_FACTOR_DEFAULT);
|
||||
} else {
|
||||
tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V << 3);
|
||||
}
|
||||
return tout_thrd;
|
||||
}
|
||||
|
||||
#undef UART_LL_TOUT_REF_FACTOR_DEFAULT
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user