v2.0.0 Add support for ESP32S2 and update ESP-IDF to 4.4 (#4996)

This is very much still work in progress and much more will change before the final 2.0.0

Some APIs have changed. New libraries have been added. LittleFS included.

Co-authored-by: Seon Rozenblum <seonr@3sprockets.com>
Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com>
Co-authored-by: geeksville <kevinh@geeksville.com>
Co-authored-by: Mike Dunston <m_dunston@comcast.net>
Co-authored-by: Unexpected Maker <seon@unexpectedmaker.com>
Co-authored-by: Seon Rozenblum <seonr@3sprockets.com>
Co-authored-by: microDev <70126934+microDev1@users.noreply.github.com>
Co-authored-by: tobozo <tobozo@users.noreply.github.com>
Co-authored-by: bobobo1618 <bobobo1618@users.noreply.github.com>
Co-authored-by: lorol <lorolouis@gmail.com>
Co-authored-by: geeksville <kevinh@geeksville.com>
Co-authored-by: Limor "Ladyada" Fried <limor@ladyada.net>
Co-authored-by: Sweety <switi.mhaiske@espressif.com>
Co-authored-by: Loick MAHIEUX <loick111@gmail.com>
Co-authored-by: Larry Bernstone <lbernstone@gmail.com>
Co-authored-by: Valerii Koval <valeros@users.noreply.github.com>
Co-authored-by: 快乐的我531 <2302004040@qq.com>
Co-authored-by: chegewara <imperiaonline4@gmail.com>
Co-authored-by: Clemens Kirchgatterer <clemens@1541.org>
Co-authored-by: Aron Rubin <aronrubin@gmail.com>
Co-authored-by: Pete Lewis <601236+lewispg228@users.noreply.github.com>
This commit is contained in:
Me No Dev
2021-04-05 14:23:58 +03:00
committed by GitHub
parent 46d5afb17f
commit 5502879a5b
5209 changed files with 826360 additions and 322816 deletions

View File

@@ -0,0 +1,219 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for ADC (esp32s2 specific part)
#pragma once
#include "hal/adc_ll.h"
#include "hal/adc_types.h"
#include_next "hal/adc_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* ADC Digital controller output data invert or not.
*
* @param adc_n ADC unit.
* @param inv_en data invert or not.
*/
#define adc_hal_digi_output_invert(adc_n, inv_en) adc_ll_digi_output_invert(adc_n, inv_en)
/**
* Sets the number of interval clock cycles for the digital controller to trigger the measurement.
* Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. Refer to ``adc_digi_clk_t``.
*
* @note The trigger interval should not be less than the sampling time of the SAR ADC.
* @param cycle The number of clock cycles for the trigger interval. The unit is the divided clock. Range: 40 ~ 4095.
*/
#define adc_hal_digi_set_trigger_interval(cycle) adc_ll_digi_set_trigger_interval(cycle)
/**
* Enable digital controller to trigger the measurement.
*/
void adc_hal_digi_enable(void);
/**
* Disable digital controller to trigger the measurement.
*/
void adc_hal_digi_disable(void);
/**
* Set ADC digital controller clock division factor. The clock divided from `APLL` or `APB` clock.
* Enable clock and select clock source for ADC digital controller.
* Expression: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
*
* @note ADC and DAC digital controller share the same frequency divider.
* Please set a reasonable frequency division factor to meet the sampling frequency of the ADC and the output frequency of the DAC.
*
* @param clk Refer to ``adc_digi_clk_t``.
*/
void adc_hal_digi_clk_config(const adc_digi_clk_t *clk);
/**
* Reset adc digital controller filter.
*
* @param adc_n ADC unit.
*/
#define adc_hal_digi_filter_reset(adc_n) adc_ll_digi_filter_reset(adc_n)
/**
* Set adc digital controller filter factor.
*
* @param adc_n ADC unit.
* @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
#define adc_hal_digi_filter_set_factor(adc_n, factor) adc_ll_digi_filter_set_factor(adc_n, factor)
/**
* Get adc digital controller filter factor.
*
* @param adc_n ADC unit.
* @param factor Expression: filter_data = (k-1)/k * last_data + new_data / k. Set values: (2, 4, 8, 16, 64).
*/
#define adc_hal_digi_filter_get_factor(adc_n, factor) adc_ll_digi_filter_get_factor(adc_n, factor)
/**
* Enable/disable adc digital controller filter.
* Filtering the ADC data to obtain smooth data at higher sampling rates.
*
* @note The filter will filter all the enabled channel data of the each ADC unit at the same time.
* @param adc_n ADC unit.
*/
#define adc_hal_digi_filter_enable(adc_n, enable) adc_ll_digi_filter_enable(adc_n, enable)
/**
* Get the filtered data of adc digital controller filter.
* The data after each measurement and filtering is updated to the DMA by the digital controller. But it can also be obtained manually through this API.
*
* @note The filter will filter all the enabled channel data of the each ADC unit at the same time.
* @param adc_n ADC unit.
* @return Filtered data.
*/
#define adc_hal_digi_filter_read_data(adc_n) adc_ll_digi_filter_read_data(adc_n)
/**
* Config monitor of adc digital controller.
*
* @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
* @param adc_n ADC unit.
* @param config Refer to ``adc_digi_monitor_t``.
*/
void adc_hal_digi_monitor_config(adc_ll_num_t adc_n, adc_digi_monitor_t *config);
/**
* Enable/disable monitor of adc digital controller.
*
* @note The monitor will monitor all the enabled channel data of the each ADC unit at the same time.
* @param adc_n ADC unit.
*/
#define adc_hal_digi_monitor_enable(adc_n, enable) adc_ll_digi_monitor_enable(adc_n, enable)
/**
* Enable interrupt of adc digital controller by bitmask.
*
* @param adc_n ADC unit.
* @param intr Interrupt bitmask.
*/
#define adc_hal_digi_intr_enable(adc_n, intr) adc_ll_digi_intr_enable(adc_n, intr)
/**
* Disable interrupt of adc digital controller by bitmask.
*
* @param adc_n ADC unit.
* @param intr Interrupt bitmask.
*/
#define adc_hal_digi_intr_disable(adc_n, intr) adc_ll_digi_intr_disable(adc_n, intr)
/**
* Clear interrupt of adc digital controller by bitmask.
*
* @param adc_n ADC unit.
* @param intr Interrupt bitmask.
*/
#define adc_hal_digi_intr_clear(adc_n, intr) adc_ll_digi_intr_clear(adc_n, intr)
/**
* Get interrupt status mask of adc digital controller.
*
* @param adc_n ADC unit.
* @return
* - intr Interrupt bitmask.
*/
#define adc_hal_digi_get_intr_status(adc_n) adc_ll_digi_get_intr_status(adc_n)
/**
* Set DMA eof num of adc digital controller.
* If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated.
*
* @param num eof num of DMA.
*/
#define adc_hal_digi_dma_set_eof_num(num) adc_ll_digi_dma_set_eof_num(num)
/**
* Enable output data to DMA from adc digital controller.
*/
#define adc_hal_digi_dma_enable() adc_ll_digi_dma_enable()
/**
* Disable output data to DMA from adc digital controller.
*/
#define adc_hal_digi_dma_disable() adc_ll_digi_dma_disable()
/**
* Reset adc digital controller.
*/
#define adc_hal_digi_reset() adc_ll_digi_reset()
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
/**
* Reset RTC controller FSM.
*/
#define adc_hal_rtc_reset() adc_ll_rtc_reset()
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* Config ADC2 module arbiter.
* The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority,
* the low priority controller will read the invalid ADC2 data, and the validity of the data can be judged by the flag bit in the data.
*
* @note Only ADC2 support arbiter.
* @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode.
* @note Default priority: Wi-Fi > RTC > Digital;
*
* @param config Refer to ``adc_arbiter_t``.
*/
void adc_hal_arbiter_config(adc_arbiter_t *config);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,31 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#define SOC_ADC1_DATA_INVERT_DEFAULT (0)
#define SOC_ADC2_DATA_INVERT_DEFAULT (0)
#define SOC_ADC_DIGI_DATA_INVERT_DEFAULT(PERIPH_NUM) (0)
#define SOC_ADC_FSM_RSTB_WAIT_DEFAULT (8)
#define SOC_ADC_FSM_START_WAIT_DEFAULT (5)
#define SOC_ADC_FSM_STANDBY_WAIT_DEFAULT (100)
#define ADC_FSM_SAMPLE_CYCLE_DEFAULT (3)
#define SOC_ADC_PWDET_CCT_DEFAULT (4)
#define SOC_ADC_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) ((PERIPH_NUM==0)? 2 : 1)
#define SOC_ADC_DIGI_SAR_CLK_DIV_DEFAULT (2)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,317 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include "soc/hwcrypto_reg.h"
#include "hal/aes_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief State of AES accelerator, busy, idle or done
*
*/
typedef enum {
ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */
ESP_AES_STATE_BUSY, /* Transform in progress */
ESP_AES_STATE_DONE, /* Transform completed */
} esp_aes_state_t;
/**
* @brief Write the encryption/decryption key to hardware
*
* @param key Key to be written to the AES hardware
* @param key_word_len Number of words in the key
*
* @return Number of bytes written to hardware, used for fault injection check
*/
static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len)
{
/* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
volatile uint8_t key_in_hardware = 0;
uint32_t *key_words = (uint32_t *)key;
for (int i = 0; i < key_word_len; i++) {
REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i));
key_in_hardware += 4;
}
return key_in_hardware;
}
/**
* @brief Sets the mode
*
* @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0
* @param key_bytes Number of bytes in the key
*/
static inline void aes_ll_set_mode(int mode, uint8_t key_bytes)
{
const uint32_t MODE_DECRYPT_BIT = 4;
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
/* See TRM for the mapping between keylength and mode bit */
REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2));
}
/**
* @brief Writes message block to AES hardware
*
* @param input Block to be written
*/
static inline void aes_ll_write_block(const void *input)
{
const uint32_t *input_words = (const uint32_t *)input;
uint32_t i0, i1, i2, i3;
/* Storing i0,i1,i2,i3 in registers not an array
helps a lot with optimisations at -Os level */
i0 = input_words[0];
REG_WRITE(AES_TEXT_IN_BASE, i0);
i1 = input_words[1];
REG_WRITE(AES_TEXT_IN_BASE + 4, i1);
i2 = input_words[2];
REG_WRITE(AES_TEXT_IN_BASE + 8, i2);
i3 = input_words[3];
REG_WRITE(AES_TEXT_IN_BASE + 12, i3);
}
/**
* @brief Read the AES block
*
* @param output the output of the transform, length = AES_BLOCK_BYTES
*/
static inline void aes_ll_read_block(void *output)
{
uint32_t *output_words = (uint32_t *)output;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < AES_BLOCK_WORDS; i++) {
output_words[i] = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Starts block transform
*
*/
static inline void aes_ll_start_transform(void)
{
REG_WRITE(AES_TRIGGER_REG, 1);
}
/**
* @brief Continue a previous started transform
*
* @note Only used when doing GCM
*/
static inline void aes_ll_cont_transform(void)
{
REG_WRITE(AES_CONTINUE_REG, 1);
}
/**
* @brief Read state of AES accelerator
*
* @return esp_aes_state_t
*/
static inline esp_aes_state_t aes_ll_get_state(void)
{
return REG_READ(AES_STATE_REG);
}
/**
* @brief Set mode of operation
*
* @note Only used for DMA transforms
*
* @param mode
*/
static inline void aes_ll_set_block_mode(esp_aes_mode_t mode)
{
REG_WRITE(AES_BLOCK_MODE_REG, mode);
}
/**
* @brief Set AES-CTR counter to INC32
*
* @note Only affects AES-CTR mode
*
*/
static inline void aes_ll_set_inc(void)
{
REG_WRITE(AES_INC_SEL_REG, 0);
}
/**
* @brief Release the DMA
*
*/
static inline void aes_ll_dma_exit(void)
{
REG_WRITE(AES_DMA_EXIT_REG, 0);
}
/**
* @brief Sets the number of blocks to be transformed
*
* @note Only used for DMA transforms
*
* @param num_blocks Number of blocks to transform
*/
static inline void aes_ll_set_num_blocks(size_t num_blocks)
{
REG_WRITE(AES_BLOCK_NUM_REG, num_blocks);
}
/*
* Write IV to hardware iv registers
*/
static inline void aes_ll_set_iv(const uint8_t *iv)
{
uint32_t *iv_words = (uint32_t *)iv;
uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE);
for (int i = 0; i < IV_WORDS; i++ ) {
REG_WRITE(&reg_addr_buf[i], iv_words[i]);
}
}
/*
* Read IV from hardware iv registers
*/
static inline void aes_ll_read_iv(uint8_t *iv)
{
uint32_t *iv_words = (uint32_t *)iv;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < IV_WORDS; i++) {
iv_words[i] = REG_READ(AES_IV_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Enable or disable DMA mode
*
* @param enable true to enable, false to disable.
*/
static inline void aes_ll_dma_enable(bool enable)
{
REG_WRITE(AES_DMA_ENABLE_REG, enable);
}
/**
* @brief Enable or disable transform completed interrupt
*
* @param enable true to enable, false to disable.
*/
static inline void aes_ll_interrupt_enable(bool enable)
{
REG_WRITE(AES_INT_ENA_REG, enable);
}
/**
* @brief Clears the interrupt
*
*/
static inline void aes_ll_interrupt_clear(void)
{
REG_WRITE(AES_INT_CLR_REG, 1);
}
/**
* @brief Reads the AES-GCM hash sub-key H
*
* @param gcm_hash hash value
*/
static inline void aes_ll_gcm_read_hash(uint8_t *gcm_hash)
{
uint32_t *hash_words = (uint32_t *)gcm_hash;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < AES_BLOCK_WORDS; i++) {
hash_words[i] = REG_READ(AES_H_BASE + (i * REG_WIDTH));
}
}
/**
* @brief Sets the number of Additional Authenticated Data (AAD) blocks
*
* @note Only affects AES-GCM
*
* @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks
*/
static inline void aes_ll_gcm_set_aad_num_blocks(size_t aad_num_blocks)
{
REG_WRITE(AES_AAD_BLOCK_NUM_REG, aad_num_blocks);
}
/**
* @brief Sets the J0 value, for more information see the GCM subchapter in the TRM
*
* @note Only affects AES-GCM
*
* @param j0 J0 value
*/
static inline void aes_ll_gcm_set_j0(const uint8_t *j0)
{
uint32_t *j0_words = (uint32_t *)j0;
uint32_t *reg_addr_buf = (uint32_t *)(AES_J_BASE);
for (int i = 0; i < AES_BLOCK_WORDS; i++ ) {
REG_WRITE(&reg_addr_buf[i], j0_words[i]);
}
}
/**
* @brief Sets the number of effective bits of incomplete blocks in plaintext/cipertext.
*
* @note Only affects AES-GCM
*
* @param num_valid_bits the number of effective bits of incomplete blocks in plaintext/cipertext.
*/
static inline void aes_ll_gcm_set_num_valid_bit(size_t num_valid_bits)
{
REG_WRITE(AES_BIT_VALID_NUM_REG, num_valid_bits);
}
/**
* @brief Read the tag after a AES-GCM transform
*
* @param tag Pointer to where to store the result with length TAG_WORDS
*/
static inline void aes_ll_gcm_read_tag(uint8_t *tag)
{
uint32_t *tag_words = (uint32_t *)tag;
const size_t REG_WIDTH = sizeof(uint32_t);
for (size_t i = 0; i < TAG_WORDS; i++) {
tag_words[i] = REG_READ(AES_T_BASE + (i * REG_WIDTH));
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,287 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "soc/periph_defs.h"
#include "soc/system_reg.h"
#include "soc/syscon_reg.h"
#include "soc/dport_access.h"
static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
{
switch (periph) {
case PERIPH_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_USB_MODULE:
return DPORT_USB_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_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_FSPI_MODULE:
return DPORT_SPI2_CLK_EN;
case PERIPH_HSPI_MODULE:
return DPORT_SPI3_CLK_EN;
case PERIPH_SPI2_DMA_MODULE:
return DPORT_SPI2_DMA_CLK_EN;
case PERIPH_SPI3_DMA_MODULE:
return DPORT_SPI3_DMA_CLK_EN;
case PERIPH_TWAI_MODULE:
return DPORT_TWAI_CLK_EN;
case PERIPH_RNG_MODULE:
return DPORT_WIFI_CLK_RNG_EN;
case PERIPH_WIFI_MODULE:
return DPORT_WIFI_CLK_WIFI_EN_M;
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_WIFI_CLK_WIFI_BT_COMMON_M;
case PERIPH_SYSTIMER_MODULE:
return DPORT_SYSTIMER_CLK_EN;
case PERIPH_DEDIC_GPIO_MODULE:
return DPORT_CLK_EN_DEDICATED_GPIO;
case PERIPH_AES_MODULE:
return DPORT_CRYPTO_AES_CLK_EN;
case PERIPH_SHA_MODULE:
return DPORT_CRYPTO_SHA_CLK_EN;
case PERIPH_RSA_MODULE:
return DPORT_CRYPTO_RSA_CLK_EN;
case PERIPH_CRYPTO_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN;
case PERIPH_SHA_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_SHA_CLK_EN;
case PERIPH_AES_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_AES_CLK_EN;
default:
return 0;
}
}
static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable)
{
(void)enable; // unused
switch (periph) {
case PERIPH_LEDC_MODULE:
return DPORT_LEDC_RST;
case PERIPH_UART0_MODULE:
return DPORT_UART_RST;
case PERIPH_UART1_MODULE:
return DPORT_UART1_RST;
case PERIPH_USB_MODULE:
return DPORT_USB_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_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_FSPI_MODULE:
return DPORT_SPI2_RST;
case PERIPH_HSPI_MODULE:
return DPORT_SPI3_RST;
case PERIPH_SPI2_DMA_MODULE:
return DPORT_SPI2_DMA_RST;
case PERIPH_SPI3_DMA_MODULE:
return DPORT_SPI3_DMA_RST;
case PERIPH_TWAI_MODULE:
return DPORT_TWAI_RST;
case PERIPH_SYSTIMER_MODULE:
return DPORT_SYSTIMER_RST;
case PERIPH_DEDIC_GPIO_MODULE:
return DPORT_RST_EN_DEDICATED_GPIO;
case PERIPH_AES_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise AES unit is held in reset also.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DS_RST);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return DPORT_CRYPTO_AES_RST;
}
case PERIPH_SHA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_HMAC_RST);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return DPORT_CRYPTO_SHA_RST;
}
case PERIPH_RSA_MODULE:
if (enable == true) {
/* also clear reset on digital signature, otherwise RSA is held in reset */
return (DPORT_CRYPTO_RSA_RST | DPORT_CRYPTO_DS_RST);
} else {
/* don't reset digital signature unit, as this resets AES also */
return DPORT_CRYPTO_RSA_RST;
}
case PERIPH_CRYPTO_DMA_MODULE:
return DPORT_CRYPTO_DMA_RST;
case PERIPH_AES_DMA_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise AES unit is held in reset also.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_DMA_RST);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DMA_RST);
}
case PERIPH_SHA_DMA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_HMAC_RST | DPORT_CRYPTO_DMA_RST);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DMA_RST);
}
default:
return 0;
}
}
static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
{
switch (periph) {
case PERIPH_DEDIC_GPIO_MODULE:
return DPORT_CPU_PERI_CLK_EN_REG;
case PERIPH_RNG_MODULE:
case PERIPH_WIFI_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_WIFI_CLK_EN_REG;
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_CRYPTO_DMA_MODULE:
case PERIPH_AES_DMA_MODULE:
case PERIPH_SHA_DMA_MODULE:
return DPORT_PERIP_CLK_EN1_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_DEDIC_GPIO_MODULE:
return DPORT_CPU_PERI_RST_EN_REG;
case PERIPH_RNG_MODULE:
case PERIPH_WIFI_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_CORE_RST_EN_REG;
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_CRYPTO_DMA_MODULE:
case PERIPH_AES_DMA_MODULE:
case PERIPH_SHA_DMA_MODULE:
return DPORT_PERIP_RST_EN1_REG;
default:
return DPORT_PERIP_RST_EN_REG;
}
}
static inline void periph_ll_enable_clk_clear_rst(periph_module_t periph)
{
DPORT_SET_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, true));
}
static inline void periph_ll_disable_clk_set_rst(periph_module_t periph)
{
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph));
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
}
static inline void IRAM_ATTR periph_ll_wifi_bt_module_enable_clk_clear_rst(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void IRAM_ATTR periph_ll_wifi_bt_module_disable_clk_set_rst(void)
{
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_BT_COMMON_M);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void periph_ll_reset(periph_module_t periph)
{
DPORT_SET_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
DPORT_CLEAR_PERI_REG_MASK(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false));
}
static inline bool IRAM_ATTR periph_ll_periph_enabled(periph_module_t periph)
{
return DPORT_REG_GET_BIT(periph_ll_get_rst_en_reg(periph), periph_ll_get_rst_en_mask(periph, false)) == 0 &&
DPORT_REG_GET_BIT(periph_ll_get_clk_en_reg(periph), periph_ll_get_clk_en_mask(periph)) != 0;
}
static inline void periph_ll_wifi_module_enable_clk_clear_rst(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
static inline void periph_ll_wifi_module_disable_clk_set_rst(void)
{
DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN_M);
DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,106 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in soc/README.md
******************************************************************************/
// CP DMA HAL usages:
// 1. Initialize HAL layer by cp_dma_hal_init, pass in the allocated descriptors for TX and RX
// 2. Enable DMA and interrupt by cp_dma_hal_start
// 3. Prepare descriptors used for TX and RX
// 4. Restart the DMA engine in case it's not in working
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "hal/dma_types.h"
#include "soc/cp_dma_struct.h"
/**
* @brief HAL context
*
*/
typedef struct {
cp_dma_dev_t *dev;
} cp_dma_hal_context_t;
typedef struct {
} cp_dma_hal_config_t;
/**
* @brief Initialize HAL layer context
*
* @param hal HAL layer context, whose memroy should be allocated at driver layer
* @param config configuration for the HAL layer
*/
void cp_dma_hal_init(cp_dma_hal_context_t *hal, const cp_dma_hal_config_t *config);
/**
* @brief Deinitialize HAL layer context
*/
void cp_dma_hal_deinit(cp_dma_hal_context_t *hal);
/**
* @brief Set descriptor base address
*/
void cp_dma_hal_set_desc_base_addr(cp_dma_hal_context_t *hal, intptr_t outlink_base, intptr_t inlink_base);
/**
* @brief Start mem2mem DMA state machine
*/
void cp_dma_hal_start(cp_dma_hal_context_t *hal);
/**
* @brief Stop mem2mem DMA state machine
*/
void cp_dma_hal_stop(cp_dma_hal_context_t *hal);
/**
* @brief Get interrupt status word
*
* @return uint32_t Interrupt status
*/
uint32_t cp_dma_hal_get_intr_status(cp_dma_hal_context_t *hal) IRAM_ATTR;
/**
* @brief Clear interrupt mask
*
* @param mask interrupt mask
*/
void cp_dma_hal_clear_intr_status(cp_dma_hal_context_t *hal, uint32_t mask) IRAM_ATTR;
/**@{*/
/**
* @brief Give the owner of descriptors between [start_desc, end_desc] to DMA, and restart DMA HW engine
*
* @param hal HAL layer context
* @param start_desc The first descriptor that carries one transaction
* @param end_desc The last descriptor that carries one transaction
*/
void cp_dma_hal_restart_tx(cp_dma_hal_context_t *hal);
void cp_dma_hal_restart_rx(cp_dma_hal_context_t *hal);
/**@}*/
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,159 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/cp_dma_struct.h"
#define CP_DMA_LL_EVENT_RX_DONE (1 << 0)
#define CP_DMA_LL_EVENT_RX_EOF (1 << 1)
#define CP_DMA_LL_EVENT_TX_DONE (1 << 2)
#define CP_DMA_LL_EVENT_TX_EOF (1 << 3)
#define CP_DMA_LL_EVENT_RX_DESC_ERR (1 << 4)
#define CP_DMA_LL_EVENT_TX_DESC_ERR (1 << 5)
#define CP_DMA_LL_EVENT_RX_DESC_EMPTY (1 << 6)
#define CP_DMA_LL_EVENT_TX_TOTAL_EOF (1 << 7)
#define CP_DMA_LL_EVENT_ALL (0xFF)
/**
* Copy DMA firstly reads data to be transferred from internal RAM,
* stores the data into DMA FIFO via an outlink,
* and then writes the data to the destination internal RAM via an inlink.
*/
static inline void cp_dma_ll_reset_in_link(cp_dma_dev_t *dev)
{
dev->dma_conf.dma_in_rst = 1;
dev->dma_conf.dma_in_rst = 0;
}
static inline void cp_dma_ll_reset_out_link(cp_dma_dev_t *dev)
{
dev->dma_conf.dma_out_rst = 1;
dev->dma_conf.dma_out_rst = 0;
}
static inline void cp_dma_ll_reset_fifo(cp_dma_dev_t *dev)
{
dev->dma_conf.dma_fifo_rst = 1;
dev->dma_conf.dma_fifo_rst = 0;
}
static inline void cp_dma_ll_reset_cmd_fifo(cp_dma_dev_t *dev)
{
dev->dma_conf.dma_cmdfifo_rst = 1;
dev->dma_conf.dma_cmdfifo_rst = 0;
}
static inline void cp_dma_ll_enable_owner_check(cp_dma_dev_t *dev, bool enable)
{
dev->dma_conf.dma_check_owner = enable;
dev->dma_conf.dma_out_auto_wrback = 1;
dev->dma_conf.dma_out_owner = 0;
dev->dma_conf.dma_in_owner = 0;
}
static inline void cp_dma_ll_enable_clock(cp_dma_dev_t *dev, bool enable)
{
dev->dma_conf.dma_clk_en = enable;
}
static inline void cp_dma_ll_enable_intr(cp_dma_dev_t *dev, uint32_t mask, bool enable)
{
if (enable) {
dev->dma_int_ena.val |= mask;
} else {
dev->dma_int_ena.val &= ~mask;
}
}
static inline __attribute__((always_inline)) uint32_t cp_dma_ll_get_intr_status(cp_dma_dev_t *dev)
{
return dev->dma_int_st.val;
}
static inline __attribute__((always_inline)) void cp_dma_ll_clear_intr_status(cp_dma_dev_t *dev, uint32_t mask)
{
dev->dma_int_clr.val = mask;
}
static inline void cp_dma_ll_tx_set_descriptor_base_addr(cp_dma_dev_t *dev, uint32_t address)
{
dev->dma_out_link.dma_outlink_addr = address;
}
static inline void cp_dma_ll_rx_set_descriptor_base_addr(cp_dma_dev_t *dev, uint32_t address)
{
dev->dma_in_link.dma_inlink_addr = address;
}
static inline void cp_dma_ll_start_tx(cp_dma_dev_t *dev, bool enable)
{
if (enable) {
dev->dma_out_link.dma_outlink_start = 1; // cleared automatically by HW
} else {
dev->dma_out_link.dma_outlink_stop = 1; // cleared automatically by HW
}
}
static inline void cp_dma_ll_start_rx(cp_dma_dev_t *dev, bool enable)
{
if (enable) {
dev->dma_in_link.dma_inlink_start = 1; // cleared automatically by HW
} else {
dev->dma_in_link.dma_inlink_stop = 1; // cleared automatically by HW
}
}
static inline void cp_dma_ll_restart_tx(cp_dma_dev_t *dev)
{
dev->dma_out_link.dma_outlink_restart = 1; // cleared automatically by HW
}
static inline void cp_dma_ll_restart_rx(cp_dma_dev_t *dev)
{
dev->dma_in_link.dma_inlink_restart = 1; // cleared automatically by HW
}
// get the address of last rx descriptor
static inline uint32_t cp_dma_ll_get_rx_eof_descriptor_address(cp_dma_dev_t *dev)
{
return dev->dma_in_eof_des_addr.dma_in_suc_eof_des_addr;
}
// get the address of last tx descriptor
static inline uint32_t cp_dma_ll_get_tx_eof_descriptor_address(cp_dma_dev_t *dev)
{
return dev->dma_out_eof_des_addr.dma_out_eof_des_addr;
}
static inline uint32_t cp_dma_ll_get_tx_status(cp_dma_dev_t *dev)
{
return dev->dma_out_st.val;
}
static inline uint32_t cp_dma_ll_get_rx_status(cp_dma_dev_t *dev)
{
return dev->dma_in_st.val;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,207 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "esp_attr.h"
#include "soc/soc_caps.h"
#include "xt_instr_macros.h"
#include "xtensa/config/specreg.h"
#include "xtensa/config/extreg.h"
#include "esp_bit_defs.h"
#include "xtensa/config/core.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t IRAM_ATTR cpu_ll_get_core_id(void)
{
return 0;
}
static inline uint32_t cpu_ll_get_cycle_count(void)
{
uint32_t result;
RSR(CCOUNT, result);
return result;
}
static inline void IRAM_ATTR cpu_ll_set_cycle_count(uint32_t val)
{
WSR(CCOUNT, val);
}
static inline void* cpu_ll_get_sp(void)
{
void *sp;
asm volatile ("mov %0, sp;" : "=r" (sp));
return sp;
}
static inline void cpu_ll_init_hwloop(void)
{
#if XCHAL_ERRATUM_572
uint32_t memctl = XCHAL_CACHE_MEMCTL_DEFAULT;
WSR(MEMCTL, memctl);
#endif // XCHAL_ERRATUM_572
}
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
{
uint32_t en;
// Set the break address register to the appropriate PC
if (id) {
WSR(IBREAKA_1, pc);
} else {
WSR(IBREAKA_0, pc);
}
// Enable the breakpoint using the break enable register
RSR(IBREAKENABLE, en);
en |= BIT(id);
WSR(IBREAKENABLE, en);
}
static inline void cpu_ll_clear_breakpoint(int id)
{
uint32_t en = 0;
uint32_t pc = 0;
// Set the break address register to the appropriate PC
if (id) {
WSR(IBREAKA_1, pc);
} else {
WSR(IBREAKA_0, pc);
}
// Enable the breakpoint using the break enable register
RSR(IBREAKENABLE, en);
en &= ~BIT(id);
WSR(IBREAKENABLE, en);
}
static inline uint32_t cpu_ll_ptr_to_pc(const void* addr)
{
return ((uint32_t) addr);
}
static inline void* cpu_ll_pc_to_ptr(uint32_t pc)
{
return (void*) ((pc & 0x3fffffffU) | 0x40000000U);
}
static inline void cpu_ll_set_watchpoint(int id,
const void* addr,
size_t size,
bool on_read,
bool on_write)
{
uint32_t dbreakc = 0x3F;
//We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
for (int x = 0; x < 7; x++) {
if (size == (size_t)(1U << x)) {
break;
}
dbreakc <<= 1;
}
dbreakc = (dbreakc & 0x3F);
if (on_read) {
dbreakc |= BIT(30);
}
if (on_write) {
dbreakc |= BIT(31);
}
// Write the break address register and the size to control
// register.
if (id) {
WSR(DBREAKA_1, (uint32_t) addr);
WSR(DBREAKC_1, dbreakc);
} else {
WSR(DBREAKA_0, (uint32_t) addr);
WSR(DBREAKC_0, dbreakc);
}
}
static inline void cpu_ll_clear_watchpoint(int id)
{
// Clear both break address register and control register
if (id) {
WSR(DBREAKA_1, 0);
WSR(DBREAKC_1, 0);
} else {
WSR(DBREAKA_0, 0);
WSR(DBREAKC_0, 0);
}
}
static inline bool cpu_ll_is_debugger_attached(void)
{
uint32_t dcr = 0;
uint32_t reg = DSRSET;
RER(reg, dcr);
return (dcr & 0x1);
}
static inline void cpu_ll_break(void)
{
__asm__ ("break 0,0");
}
static inline void cpu_ll_set_vecbase(const void* vecbase)
{
asm volatile ("wsr %0, vecbase" :: "r" (vecbase));
}
static inline uint32_t cpu_ll_read_dedic_gpio_in(void)
{
uint32_t value = 0;
asm volatile("get_gpio_in %0" : "=r"(value) : :);
return value;
}
static inline uint32_t cpu_ll_read_dedic_gpio_out(void)
{
uint32_t value = 0;
asm volatile("rur.gpio_out %0" : "=r"(value) : :);
return value;
}
static inline void cpu_ll_write_dedic_gpio_all(uint32_t value)
{
asm volatile("wur.gpio_out %0"::"r"(value):);
}
static inline void cpu_ll_write_dedic_gpio_mask(uint32_t mask, uint32_t value)
{
asm volatile("wr_mask_gpio_out %0, %1" : : "r"(value), "r"(mask):);
}
static inline void cpu_ll_waiti(void)
{
asm volatile ("waiti 0\n");
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,102 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/hwcrypto_reg.h"
#include "soc/dport_reg.h"
typedef enum {
CRYPTO_DMA_AES= 0,
CRYPTO_DMA_SHA,
} crypto_dma_mode_t;
/**
* @brief Resets the DMA
*
*/
static inline void crypto_dma_ll_reset(void)
{
SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST);
}
/**
* @brief Selects the crypto DMA mode
*
* @param mode Mode to use, AES or SHA
*/
static inline void crypto_dma_ll_set_mode(crypto_dma_mode_t mode)
{
REG_WRITE(CRYPTO_DMA_AES_SHA_SELECT_REG, mode);
}
/**
* @brief Sets up the outlink for a transfer
*
* @param outlink_addr Address of the outlink buffer
*/
static inline void crypto_dma_ll_outlink_set(uint32_t outlink_addr)
{
CLEAR_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_ADDR);
SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, outlink_addr & OUT_LINK_REG_OUTLINK_ADDR);
}
/**
* @brief Sets up the inlink for a transfer
*
* @param inlink_addr Address of the inlink buffer
*/
static inline void crypto_dma_ll_inlink_set(uint32_t inlink_addr)
{
CLEAR_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_ADDR);
SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, inlink_addr & IN_LINK_REG_INLINK_ADDR);
}
/**
* @brief Starts the outlink
*
*/
static inline void crypto_dma_ll_outlink_start(void)
{
SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_START);
}
/**
* @brief Starts the inlink
*
*/
static inline void crypto_dma_ll_inlink_start(void)
{
SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_START);
}
static inline bool crypto_dma_ll_inlink_is_eof(void)
{
return ((REG_READ(CRYPTO_DMA_INT_RAW_REG) & INT_RAW_IN_SUC_EOF) == INT_RAW_IN_SUC_EOF);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,76 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for DAC (esp32s2 specific part)
#pragma once
#include "hal/dac_ll.h"
#include "hal/dac_types.h"
#include_next "hal/dac_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* Digital controller initialization.
*/
void dac_hal_digi_init(void);
/**
* Digital controller deinitialization.
*/
void dac_hal_digi_deinit(void);
/**
* Setting the DAC digital controller.
*
* @param cfg Pointer to digital controller paramter.
*/
void dac_hal_digi_controller_config(const dac_digi_config_t *cfg);
/**
* DAC digital controller start output voltage.
*/
void dac_hal_digi_start(void);
/**
* DAC digital controller stop output voltage.
*/
void dac_hal_digi_stop(void);
/**
* Reset DAC digital controller FIFO.
*/
#define dac_hal_digi_fifo_reset() dac_ll_digi_fifo_reset()
/**
* Reset DAC digital controller.
*/
#define dac_hal_digi_reset() dac_ll_digi_reset()
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,288 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stdlib.h>
#include "soc/dac_periph.h"
#include "hal/dac_types.h"
#include "soc/apb_saradc_struct.h"
#include "soc/apb_saradc_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
DAC common setting
---------------------------------------------------------------*/
/**
* 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)
{
SENS.sar_dac_ctrl1.dac_clkgate_en = 1;
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;
if (RTCIO.pad_dac[0].xpd_dac == 0 && RTCIO.pad_dac[1].xpd_dac == 0) {
SENS.sar_dac_ctrl1.dac_clkgate_en = 0;
}
}
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
/**
* 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;
}
}
/**
* Reset dac by software.
*/
static inline void dac_ll_rtc_reset(void)
{
SENS.sar_dac_ctrl1.dac_reset = 1;
SENS.sar_dac_ctrl1.dac_reset = 0;
}
/**
* 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_amp_ctrl3.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);
}
}
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/************************************/
/* DAC DMA API's */
/************************************/
/**
* Enable/disable invert the DAC digital controller clock signal.
*
* @param enable true or false.
*/
static inline void dac_ll_digi_clk_inv(bool enable)
{
SENS.sar_dac_ctrl1.dac_clk_inv = enable;
}
/**
* Enable/disable DAC-DMA mode for dac digital controller.
*/
static inline void dac_ll_digi_enable_dma(bool enable)
{
SENS.sar_dac_ctrl1.dac_dig_force = enable;
APB_SARADC.apb_dac_ctrl.apb_dac_trans = enable;
}
/**
* Sets the number of interval clock cycles for the digital controller to trigger the DAC output.
* Expression: `dac_output_freq` = `controller_clk` / interval.
*
* @note The clocks of the DAC digital controller use the ADC digital controller clock divider.
*
* @param cycle The number of clock cycles for the trigger output interval. The unit is the divided clock.
*/
static inline void dac_ll_digi_set_trigger_interval(uint32_t cycle)
{
APB_SARADC.apb_dac_ctrl.dac_timer_target = cycle;
}
/**
* Enable/disable DAC digital controller to trigger the DAC output.
*
* @param enable true or false.
*/
static inline void dac_ll_digi_trigger_output(bool enable)
{
APB_SARADC.apb_dac_ctrl.dac_timer_en = enable;
}
/**
* Set DAC conversion mode for digital controller.
*
* @param mode Conversion mode select. See ``dac_digi_convert_mode_t``.
*/
static inline void dac_ll_digi_set_convert_mode(dac_digi_convert_mode_t mode)
{
if (mode == DAC_CONV_NORMAL) {
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 0;
} else {
APB_SARADC.apb_dac_ctrl.apb_dac_alter_mode = 1;
}
}
/**
* Reset FIFO of DAC digital controller.
*/
static inline void dac_ll_digi_fifo_reset(void)
{
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 1;
APB_SARADC.apb_dac_ctrl.dac_reset_fifo = 0;
}
/**
* Reset DAC digital controller.
*/
static inline void dac_ll_digi_reset(void)
{
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 1;
APB_SARADC.apb_dac_ctrl.apb_dac_rst = 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,110 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/dedic_gpio_struct.h"
static inline void dedic_gpio_ll_enable_instruction_access_out(dedic_dev_t *dev, uint32_t channel_mask, bool enable)
{
if (enable) {
dev->gpio_out_cpu.val |= channel_mask;
} else {
dev->gpio_out_cpu.val &= ~channel_mask;
}
}
static inline void dedic_gpio_ll_write_all(dedic_dev_t *dev, uint32_t value)
{
dev->gpio_out_drt.val = value;
}
static inline void dedic_gpio_ll_write_mask(dedic_dev_t *dev, uint32_t channel_mask, uint32_t value)
{
dedic_gpio_out_msk_reg_t d = {
.gpio_out_msk = channel_mask,
.gpio_out_value = value
};
dev->gpio_out_msk.val = d.val;
}
static inline void dedic_gpio_ll_set_channel(dedic_dev_t *dev, uint32_t channel)
{
dev->gpio_out_idv.val = 1 << (2 * channel);
}
static inline void dedic_gpio_ll_clear_channel(dedic_dev_t *dev, uint32_t channel)
{
dev->gpio_out_idv.val = 2 << (2 * channel);
}
static inline void dedic_gpio_ll_toggle_channel(dedic_dev_t *dev, uint32_t channel)
{
dev->gpio_out_idv.val = 3 << (2 * channel);
}
static inline uint32_t dedic_gpio_ll_read_out_all(dedic_dev_t *dev)
{
return dev->gpio_out_scan.gpio_out_status;
}
static inline uint32_t dedic_gpio_ll_read_in_all(dedic_dev_t *dev)
{
return dev->gpio_in_scan.gpio_in_status;
}
static inline void dedic_gpio_ll_set_input_delay(dedic_dev_t *dev, uint32_t channel, uint32_t delay_cpu_clks)
{
dev->gpio_in_dly.val &= ~(3 << (2 * channel));
dev->gpio_in_dly.val |= (delay_cpu_clks & 0x03) << (2 * channel);
}
static inline uint32_t dedic_gpio_ll_get_input_delay(dedic_dev_t *dev, uint32_t channel)
{
return (dev->gpio_in_dly.val & (3 << (2 * channel)) >> (2 * channel));
}
static inline void dedic_gpio_ll_set_interrupt_type(dedic_dev_t *dev, uint32_t channel, uint32_t type)
{
dev->gpio_intr_rcgn.val &= ~(7 << (3 * channel));
dev->gpio_intr_rcgn.val |= (type & 0x07) << (3 * channel);
}
static inline void dedic_gpio_ll_enable_interrupt(dedic_dev_t *dev, uint32_t channel_mask, bool enable)
{
if (enable) {
dev->gpio_intr_rls.val |= channel_mask;
} else {
dev->gpio_intr_rls.val &= ~channel_mask;
}
}
static inline uint32_t __attribute__((always_inline)) dedic_gpio_ll_get_interrupt_status(dedic_dev_t *dev)
{
return dev->gpio_intr_st.val;
}
static inline void __attribute__((always_inline)) dedic_gpio_ll_clear_interrupt_status(dedic_dev_t *dev, uint32_t channel_mask)
{
dev->gpio_intr_clr.val = channel_mask;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,536 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32-S2 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)
#define GPIO_LL_PRO_CPU_INTR_ENA (BIT(0))
#define GPIO_LL_PRO_CPU_NMI_INTR_ENA (BIT(1))
/**
* @brief Enable pull-up on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
/**
* @brief Disable pull-up on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU);
}
/**
* @brief Enable pull-down on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_SET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
/**
* @brief Disable pull-down on GPIO.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
REG_CLR_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD);
}
/**
* @brief GPIO set interrupt trigger type
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param intr_type Interrupt type, select from gpio_int_type_t
*/
static inline void gpio_ll_set_intr_type(gpio_dev_t *hw, gpio_num_t gpio_num, gpio_int_type_t intr_type)
{
hw->pin[gpio_num].int_type = intr_type;
}
/**
* @brief Get GPIO interrupt status
*
* @param hw Peripheral GPIO hardware instance address.
* @param core_id interrupt core id
* @param status interrupt status
*/
static inline void gpio_ll_get_intr_status(gpio_dev_t *hw, uint32_t core_id, uint32_t *status)
{
*status = hw->pcpu_int;
}
/**
* @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 = hw->pcpu_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) {
GPIO.pin[gpio_num].int_ena = GPIO_LL_PRO_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)
{
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD);
}
/**
* @brief Enable gpio pad hold function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
*/
static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
}
/**
* @brief Disable gpio pad hold function.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number, only support output GPIOs
*/
static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_PAD_HOLD_REG, GPIO_HOLD_MASK[gpio_num]);
}
/**
* @brief Set pad input to a peripheral signal through the IOMUX.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number of the pad.
* @param signal_idx Peripheral signal id to input. One of the ``*_IN_IDX`` signals in ``soc/gpio_sig_map.h``.
*/
static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx)
{
hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0;
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio]);
}
/**
* @brief Set peripheral output to an GPIO pad through the IOMUX.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num gpio_num GPIO number of the pad.
* @param func The function number of the peripheral pin to output pin.
* One of the ``FUNC_X_*`` of specified pin (X) in ``soc/io_mux_reg.h``.
* @param oen_inv True if the output enable needs to be inverted, otherwise False.
*/
static inline void gpio_ll_iomux_out(gpio_dev_t *hw, uint8_t gpio_num, int func, uint32_t oen_inv)
{
hw->func_out_sel_cfg[gpio_num].oen_sel = 0;
hw->func_out_sel_cfg[gpio_num].oen_inv_sel = oen_inv;
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], func);
}
static inline void gpio_ll_force_hold_all(gpio_dev_t *hw)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_HOLD);
}
static inline void gpio_ll_force_unhold_all(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_HOLD);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD);
SET_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_CLR_DG_PAD_AUTOHOLD);
}
/**
* @brief Enable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pin used for wakeup from sleep.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_SEL_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-up in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLUP_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO pull-down in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_PULLDOWN_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO input in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Disable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_DISABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
/**
* @brief Enable GPIO output in sleep mode.
*
* @param hw Peripheral GPIO hardware instance address.
* @param gpio_num GPIO number
*/
static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, gpio_num_t gpio_num)
{
PIN_SLP_OUTPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,375 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include <stdlib.h>
#include "soc/spi_periph.h"
#include "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
#define gpspi_flash_ll_get_hw(host_id) ( ((host_id)==SPI2_HOST) ? &GPSPI2 : (\
((host_id)==SPI3_HOST) ? &GPSPI3 : (\
{abort();(spi_dev_t*)0;}\
)) )
#define gpspi_flash_ll_hw_get_id(dev) ( ((dev) == (void*)&GPSPI2) ? SPI2_HOST : (\
((dev) == (void*)&GPSPI3) ? SPI3_HOST : (\
-1 \
)) )
typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t;
//Supported clock register values
#define GPSPI_FLASH_LL_CLKREG_VAL_5MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x0000F1CF}) ///< Clock set to 5 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_10MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x000070C7}) ///< Clock set to 10 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_20MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00003043}) ///< Clock set to 20 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_26MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00002002}) ///< Clock set to 26 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_40MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x00001001}) ///< Clock set to 40 MHz
#define GPSPI_FLASH_LL_CLKREG_VAL_80MHZ ((gpspi_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/*------------------------------------------------------------------------------
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_reset(spi_dev_t *dev)
{
dev->user.val = 0;
dev->ctrl.val = 0;
}
/**
* Check whether the previous operation is done.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if last command is done, otherwise false.
*/
static inline bool gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev)
{
return (dev->cmd.val == 0);
}
/**
* Get the read data from the buffer after ``gpspi_flash_ll_read`` is done.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer to hold the output data
* @param read_len Length to get out of the buffer
*/
static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len)
{
if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) {
// If everything is word-aligned, do a faster memcpy
memcpy(buffer, (void *)dev->data_buf, read_len);
} else {
// Otherwise, slow(er) path copies word by word
int copy_len = read_len;
for (size_t i = 0; i < (read_len + 3) / 4; i++) {
int word_len = MIN(sizeof(uint32_t), copy_len);
uint32_t word = dev->data_buf[i];
memcpy(buffer, &word, word_len);
buffer = (void *)((intptr_t)buffer + word_len);
copy_len -= word_len;
}
}
}
/**
* Write a word to the data buffer.
*
* @param dev Beginning address of the peripheral registers.
* @param word Data to write at address 0.
*/
static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word)
{
dev->data_buf[0] = word;
}
/**
* Set the data to be written in the data buffer.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer holding the data
* @param length Length of data in bytes.
*/
static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length)
{
// Load data registers, word at a time
int num_words = (length + 3) / 4;
for (int i = 0; i < num_words; i++) {
uint32_t word = 0;
uint32_t word_len = MIN(length, sizeof(word));
memcpy(&word, buffer, word_len);
dev->data_buf[i] = word;
length -= word_len;
buffer = (void *)((intptr_t)buffer + word_len);
}
}
/**
* Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases,
* should be configured before this is called.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_user_start(spi_dev_t *dev)
{
dev->cmd.usr = 1;
}
/**
* Check whether the host is idle to perform new commands.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if the host is idle, otherwise false
*/
static inline bool gpspi_flash_ll_host_idle(const spi_dev_t *dev)
{
return dev->fsm.st == 0;
}
/**
* Set phases for user-defined transaction to read
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void gpspi_flash_ll_read_phase(spi_dev_t *dev)
{
typeof (dev->user) user = {
.usr_command = 1,
.usr_mosi = 0,
.usr_miso = 1,
.usr_addr = 1,
};
dev->user = user;
}
/*------------------------------------------------------------------------------
* Configs
*----------------------------------------------------------------------------*/
/**
* Select which pin to use for the flash
*
* @param dev Beginning address of the peripheral registers.
* @param pin Pin ID to use, 0-2. Set to other values to disable all the CS pins.
*/
static inline void gpspi_flash_ll_set_cs_pin(spi_dev_t *dev, int pin)
{
dev->misc.cs0_dis = (pin != 0);
dev->misc.cs1_dis = (pin != 1);
dev->misc.cs2_dis = (pin != 2);
dev->misc.cs3_dis = (pin != 3);
dev->misc.cs4_dis = (pin != 4);
dev->misc.cs5_dis = (pin != 5);
}
/**
* Set the read io mode.
*
* @param dev Beginning address of the peripheral registers.
* @param read_mode I/O mode to use in the following transactions.
*/
static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
typeof (dev->user) user = dev->user;
ctrl.val &= ~(SPI_FCMD_QUAD_M | SPI_FADDR_QUAD_M | SPI_FREAD_QUAD_M | SPI_FCMD_DUAL_M | SPI_FADDR_DUAL_M | SPI_FREAD_DUAL_M);
user.val &= ~(SPI_FWRITE_QUAD_M | SPI_FWRITE_DUAL_M);
switch (read_mode) {
case SPI_FLASH_FASTRD:
//the default option
case SPI_FLASH_SLOWRD:
break;
case SPI_FLASH_QIO:
ctrl.fread_quad = 1;
ctrl.faddr_quad = 1;
user.fwrite_quad = 1;
break;
case SPI_FLASH_QOUT:
ctrl.fread_quad = 1;
user.fwrite_quad = 1;
break;
case SPI_FLASH_DIO:
ctrl.fread_dual = 1;
ctrl.faddr_dual = 1;
user.fwrite_dual = 1;
break;
case SPI_FLASH_DOUT:
ctrl.fread_dual = 1;
user.fwrite_dual = 1;
break;
default:
abort();
}
dev->ctrl = ctrl;
dev->user = user;
}
/**
* Set clock frequency to work at.
*
* @param dev Beginning address of the peripheral registers.
* @param clock_val pointer to the clock value to set
*/
static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock_reg_t *clock_val)
{
dev->clock = *clock_val;
}
/**
* Set the input length, in bits.
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of input, in bits.
*/
static inline void gpspi_flash_ll_set_miso_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the output length, in bits (not including command, address and dummy
* phases)
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of output, in bits.
*/
static inline void gpspi_flash_ll_set_mosi_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void gpspi_flash_ll_set_command(spi_dev_t *dev, uint8_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
/**
* Get the address length that is set in register, in bits.
*
* @param dev Beginning address of the peripheral registers.
*
*/
static inline int gpspi_flash_ll_get_addr_bitlen(spi_dev_t *dev)
{
return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0;
}
/**
* Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of the address, in bits
*/
static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitlen)
{
dev->user1.usr_addr_bitlen = (bitlen - 1);
dev->user.usr_addr = bitlen ? 1 : 0;
}
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
// The blank region should be all ones
uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen);
dev->addr = (addr << (32 - bitlen)) | padding_ones;
}
/**
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr)
{
dev->addr = addr;
}
/**
* Set the length of dummy cycles.
*
* @param dev Beginning address of the peripheral registers.
* @param dummy_n Cycles of dummy phases
*/
static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n)
{
dev->user.usr_dummy = dummy_n ? 1 : 0;
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
/**
* Set D/Q output level during dummy phase
*
* @param dev Beginning address of the peripheral registers.
* @param out_en whether to enable IO output for dummy phase
* @param out_level dummy output level
*/
static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev)
{
dev->ctrl.dummy_out = out_en;
dev->ctrl.q_pol = out_lev;
dev->ctrl.d_pol = out_lev;
}
static inline void gpspi_flash_ll_set_hold(spi_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,911 @@
// 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
#define I2C_LL_INTR_MASK (0x1ffff) /*!< I2C all interrupt bitmap */
/**
* @brief I2C hardware cmd register filed.
*/
typedef union {
struct {
uint32_t byte_num: 8,
ack_en: 1,
ack_exp: 1,
ack_val: 1,
op_code: 3,
reserved14: 17,
done: 1;
};
uint32_t val;
} i2c_hw_cmd_t;
/**
* @brief I2C interrupt event
*/
typedef enum {
I2C_INTR_EVENT_ERR,
I2C_INTR_EVENT_ARBIT_LOST, /*!< I2C arbition lost event */
I2C_INTR_EVENT_NACK, /*!< I2C NACK event */
I2C_INTR_EVENT_TOUT, /*!< I2C time out event */
I2C_INTR_EVENT_END_DET, /*!< I2C end detected event */
I2C_INTR_EVENT_TRANS_DONE, /*!< I2C trans done event */
I2C_INTR_EVENT_RXFIFO_FULL, /*!< I2C rxfifo full event */
I2C_INTR_EVENT_TXFIFO_EMPTY, /*!< I2C txfifo empty event */
} i2c_intr_event_t;
/**
* @brief Data structure for calculating I2C bus timing.
*/
typedef struct {
uint16_t scl_low; /*!< I2C scl low period */
uint16_t scl_high; /*!< I2C scl hight period */
uint16_t scl_wait_high; /*!< I2C scl wait_high period */
uint16_t sda_hold; /*!< I2C scl low period */
uint16_t sda_sample; /*!< I2C sda sample time */
uint16_t setup; /*!< I2C start and stop condition setup period */
uint16_t hold; /*!< I2C start and stop condition hold period */
uint16_t tout; /*!< I2C bus timeout period */
} i2c_clk_cal_t;
// I2C operation mode command
#define I2C_LL_CMD_RESTART 0 /*!<I2C restart command */
#define I2C_LL_CMD_WRITE 1 /*!<I2C write command */
#define I2C_LL_CMD_READ 2 /*!<I2C read command */
#define I2C_LL_CMD_STOP 3 /*!<I2C stop command */
#define I2C_LL_CMD_END 4 /*!<I2C end command */
// Get the I2C hardware instance
#define I2C_LL_GET_HW(i2c_num) (((i2c_num) == 0) ? &I2C0 : &I2C1)
// Get the I2C hardware FIFO address
#define I2C_LL_GET_FIFO_ADDR(i2c_num) (I2C_DATA_APB_REG(i2c_num))
// I2C master TX interrupt bitmap
#define I2C_LL_MASTER_TX_INT (I2C_NACK_INT_ENA_M|I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
// I2C master RX interrupt bitmap
#define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M)
// I2C slave TX interrupt bitmap
#define I2C_LL_SLAVE_TX_INT (I2C_TXFIFO_WM_INT_ENA_M)
// I2C slave RX interrupt bitmap
#define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M)
// I2C source clock
#define I2C_LL_CLK_SRC_FREQ(src_clk) (((src_clk) == I2C_SCLK_REF_TICK) ? 1000*1000 : 80*1000*1000); // Another clock is APB clock
// I2C max timeout value
#define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V
/**
* @brief Calculate I2C bus frequency
*
* @param source_clk I2C source clock
* @param bus_freq I2C bus frequency
* @param clk_cal Pointer to accept the clock configuration
*
* @return None
*/
static inline void i2c_ll_cal_bus_clk(uint32_t source_clk, uint32_t bus_freq, i2c_clk_cal_t *clk_cal)
{
uint32_t half_cycle = source_clk / bus_freq / 2;
//SCL
clk_cal->scl_low = half_cycle;
// default, scl_wait_high < scl_high
clk_cal->scl_high = half_cycle / 2 + 2;
clk_cal->scl_wait_high = half_cycle - clk_cal->scl_high;
clk_cal->sda_hold = half_cycle / 2;
// scl_wait_high < sda_sample <= scl_high
clk_cal->sda_sample = half_cycle / 2 - 1;
clk_cal->setup = half_cycle;
clk_cal->hold = half_cycle;
//default we set the timeout value to 10 bus cycles
clk_cal->tout = half_cycle * 20;
}
/**
* @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 - 1;
hw->scl_high_period.period = bus_cfg->scl_high;
hw->scl_high_period.scl_wait_high_period = bus_cfg->scl_wait_high;
//sda sample
hw->sda_hold.time = bus_cfg->sda_hold;
hw->sda_sample.time = bus_cfg->sda_sample;
//setup
hw->scl_rstart_setup.time = bus_cfg->setup;
hw->scl_stop_setup.time = bus_cfg->setup;
//hold
hw->scl_start_hold.time = bus_cfg->hold - 1;
hw->scl_stop_hold.time = bus_cfg->hold;
hw->timeout.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, hight_period > 2)
* @param low_period The I2C SCL low period (in APB cycle, low_period > 1)
*
* @return None.
*/
static inline void i2c_ll_set_scl_timing(i2c_dev_t *hw, int hight_period, int low_period)
{
hw->scl_low_period.period = low_period-1;
hw->scl_high_period.period = hight_period/2+2;
hw->scl_high_period.scl_wait_high_period = hight_period - hw->scl_high_period.period;
}
/**
* @brief Clear I2C interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be cleared
*
* @return None
*/
static inline void i2c_ll_clr_intsts_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_clr.val = mask;
}
/**
* @brief Enable I2C interrupt
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be enabled
*
* @return None
*/
static inline void i2c_ll_enable_intr_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_ena.val |= mask;
}
/**
* @brief Disable I2C interrupt
*
* @param hw Beginning address of the peripheral registers
* @param mask Interrupt mask needs to be disabled
*
* @return None
*/
static inline void i2c_ll_disable_intr_mask(i2c_dev_t *hw, uint32_t mask)
{
hw->int_ena.val &= (~mask);
}
/**
* @brief Get I2C interrupt status
*
* @param hw Beginning address of the peripheral registers
*
* @return I2C interrupt status
*/
static inline uint32_t i2c_ll_get_intsts_mask(i2c_dev_t *hw)
{
return hw->int_status.val;
}
/**
* @brief Configure I2C memory access mode, FIFO mode or non-FIFO mode
*
* @param hw Beginning address of the peripheral registers
* @param fifo_mode_en Set true to enable FIFO access mode, else, set it false
*
* @return None
*/
static inline void i2c_ll_set_fifo_mode(i2c_dev_t *hw, bool fifo_mode_en)
{
hw->fifo_conf.nonfifo_en = fifo_mode_en ? 0 : 1;
}
/**
* @brief Configure I2C timeout
*
* @param hw Beginning address of the peripheral registers
* @param tout_num The I2C timeout value needs to be set (in APB cycle)
*
* @return None
*/
static inline void i2c_ll_set_tout(i2c_dev_t *hw, int tout)
{
hw->timeout.tout = tout;
hw->timeout.time_out_en = tout > 0;
}
/**
* @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-1;
}
/**
* @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_wm_thrhd = empty_thr;
}
/**
* @brief Set I2C rxFIFO full threshold
*
* @param hw Beginning address of the peripheral registers
* @param full_thr The rxFIFO full threshold
*
* @return None
*/
static inline void i2c_ll_set_rxfifo_full_thr(i2c_dev_t *hw, uint8_t full_thr)
{
hw->fifo_conf.rx_fifo_wm_thrhd = full_thr;
}
/**
* @brief Set the I2C data mode, LSB or MSB
*
* @param hw Beginning address of the peripheral registers
* @param tx_mode Tx data bit mode
* @param rx_mode Rx data bit mode
*
* @return None
*/
static inline void i2c_ll_set_data_mode(i2c_dev_t *hw, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode)
{
hw->ctr.tx_lsb_first = tx_mode;
hw->ctr.rx_lsb_first = rx_mode;
}
/**
* @brief Get the I2C data mode
*
* @param hw Beginning address of the peripheral registers
* @param tx_mode Pointer to accept the received bytes mode
* @param rx_mode Pointer to accept the sended bytes mode
*
* @return None
*/
static inline void i2c_ll_get_data_mode(i2c_dev_t *hw, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode)
{
*tx_mode = hw->ctr.tx_lsb_first;
*rx_mode = hw->ctr.rx_lsb_first;
}
/**
* @brief Get I2C sda timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param sda_sample Pointer to accept the SDA sample timing configuration
* @param sda_hold Pointer to accept the SDA hold timing configuration
*
* @return None
*/
static inline void i2c_ll_get_sda_timing(i2c_dev_t *hw, int *sda_sample, int *sda_hold)
{
*sda_hold = hw->sda_hold.time;
*sda_sample = hw->sda_sample.time;
}
/**
* @brief Get the I2C hardware version
*
* @param hw Beginning address of the peripheral registers
*
* @return The I2C hardware version
*/
static inline uint32_t i2c_ll_get_hw_version(i2c_dev_t *hw)
{
return hw->date;
}
/**
* @brief Check if the I2C bus is busy
*
* @param hw Beginning address of the peripheral registers
*
* @return True if I2C state machine is busy, else false will be returned
*/
static inline bool i2c_ll_is_bus_busy(i2c_dev_t *hw)
{
return hw->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+1;
}
/**
* @brief Get I2C stop timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param setup_time Pointer to accept the stop condition setup period
* @param hold_time Pointer to accept the stop condition hold period
*
* @return None
*/
static inline void i2c_ll_get_stop_timing(i2c_dev_t *hw, int *setup_time, int *hold_time)
{
*setup_time = hw->scl_stop_setup.time;
*hold_time = hw->scl_stop_hold.time;
}
/**
* @brief Get I2C SCL timing configuration
*
* @param hw Beginning address of the peripheral registers
* @param high_period Pointer to accept the SCL high period
* @param low_period Pointer to accept the SCL low period
*
* @return None
*/
static inline void i2c_ll_get_scl_timing(i2c_dev_t *hw, int *high_period, int *low_period)
{
*high_period = hw->scl_high_period.period + hw->scl_high_period.scl_wait_high_period;
*low_period = hw->scl_low_period.period + 1;
}
/**
* @brief Write the I2C hardware txFIFO
*
* @param hw Beginning address of the peripheral registers
* @param ptr Pointer to data buffer
* @param len Amount of data needs to be writen
*
* @return None.
*/
static inline void i2c_ll_write_txfifo(i2c_dev_t *hw, uint8_t *ptr, uint8_t len)
{
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)
{
uint32_t fifo_addr = (hw == &I2C0) ? 0x6001301c : 0x6002701c;
for(int i = 0; i < len; i++) {
ptr[i] = READ_PERI_REG(fifo_addr);
}
}
/**
* @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)
{
hw->ctr.fsm_rst = 1;
}
/**
* @brief Clear I2C bus, when the slave is stuck in a deadlock and keeps pulling the bus low,
* master can controls the SCL bus to generate 9 CLKs.
*
* Note: The master cannot detect if deadlock happens, but when the scl_st_to interrupt is generated, a deadlock may occur.
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_clr_bus(i2c_dev_t *hw)
{
hw->scl_sp_conf.scl_rst_slv_num = 9;
hw->scl_sp_conf.scl_rst_slv_en = 0;
hw->scl_sp_conf.scl_rst_slv_en = 1;
}
/**
* @brief Set I2C source clock
*
* @param hw Beginning address of the peripheral registers
* @param src_clk Source clock of the I2C
*
* @return None
*/
static inline void i2c_ll_set_source_clk(i2c_dev_t *hw, i2c_sclk_t src_clk)
{
// src_clk : (1) for APB_CLK, (0) for REF_CLK
hw->ctr.ref_always_on = (src_clk == I2C_SCLK_REF_TICK) ? 0 : 1;
}
/**
* @brief Get I2C master interrupt event
*
* @param hw Beginning address of the peripheral registers
* @param event Pointer to accept the interrupt event
*
* @return None
*/
static inline void i2c_ll_master_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
{
typeof(hw->int_status) int_sts = hw->int_status;
if (int_sts.arbitration_lost) {
*event = I2C_INTR_EVENT_ARBIT_LOST;
} else if (int_sts.nack) {
*event = I2C_INTR_EVENT_NACK;
} else if (int_sts.time_out) {
*event = I2C_INTR_EVENT_TOUT;
} else if (int_sts.end_detect) {
*event = I2C_INTR_EVENT_END_DET;
} else if (int_sts.trans_complete) {
*event = I2C_INTR_EVENT_TRANS_DONE;
} else {
*event = I2C_INTR_EVENT_ERR;
}
}
/**
* @brief Get I2C slave interrupt event
*
* @param hw Beginning address of the peripheral registers
* @param event Pointer to accept the interrupt event
*
* @return None
*/
static inline void i2c_ll_slave_get_event(i2c_dev_t *hw, i2c_intr_event_t *event)
{
typeof(hw->int_status) int_sts = hw->int_status;
if (int_sts.tx_fifo_wm) {
*event = I2C_INTR_EVENT_TXFIFO_EMPTY;
} else if (int_sts.trans_complete) {
*event = I2C_INTR_EVENT_TRANS_DONE;
} else if (int_sts.rx_fifo_wm) {
*event = I2C_INTR_EVENT_RXFIFO_FULL;
} else {
*event = I2C_INTR_EVENT_ERR;
}
}
/**
* @brief Init I2C master
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_master_init(i2c_dev_t *hw)
{
typeof(hw->ctr) ctrl_reg;
ctrl_reg.val = 0;
ctrl_reg.ms_mode = 1;
ctrl_reg.sda_force_out = 1;
ctrl_reg.scl_force_out = 1;
hw->ctr.val = ctrl_reg.val;
}
/**
* @brief Enable I2C internal open-drain mode
* If internal open-drain of the I2C module is disabled, scl and sda gpio should be configured in open-drain mode.
* Otherwise it is not needed.
*
* @param hw Beginning address of the peripheral registers
* @param internal_od_ena Set true to enble internal open-drain, otherwise, set it false.
*
* @return None
*/
static inline void i2c_ll_internal_od_enable(i2c_dev_t *hw, bool internal_od_ena)
{
hw->ctr.sda_force_out = (internal_od_ena == false);
hw->ctr.scl_force_out = (internal_od_ena == false);
}
/**
* @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;
//Open-drain output via GPIO
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;
hw->scl_stretch_conf.slave_scl_stretch_en = 0;
}
/**
* @brief Update I2C configuration
*
* @param hw Beginning address of the peripheral registers
*
* @return None
*/
static inline void i2c_ll_update(i2c_dev_t *hw)
{
;// ESP32S2 do not support
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,765 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32-S2 I2S register operations
#pragma once
#include <stdbool.h>
#include "soc/i2s_periph.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Get I2S hardware instance with giving i2s num
#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL)
#define I2S_INTR_IN_SUC_EOF BIT(9)
#define I2S_INTR_OUT_EOF BIT(12)
#define I2S_INTR_IN_DSCR_ERR BIT(13)
#define I2S_INTR_OUT_DSCR_ERR BIT(14)
#define I2S_INTR_MAX (0xFFFFFFFF)
/**
* @brief Reset rx fifo
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw)
{
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 tx dma equal
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set tx dma equal
*/
static inline void i2s_ll_set_tx_dma_equal(i2s_dev_t *hw, uint32_t val)
{
hw->conf.tx_dma_equal = val;
}
/**
* @brief Set I2S rx dma equal
*
* @param hw Peripheral I2S hardware instance address.
* @param val value to set rx dma equal
*/
static inline void i2s_ll_set_rx_dma_equal(i2s_dev_t *hw, uint32_t val)
{
hw->conf.rx_dma_equal = 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)
{
hw->rx_eof_num = val;
}
/**
* @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.clk_sel = (val == 1) ? 1 : 2;
}
/**
* @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 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 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 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;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,114 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#include "soc/soc.h"
#include "xtensa/xtensa_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief enable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be enabled
*/
static inline void intr_cntrl_ll_enable_interrupts(uint32_t mask)
{
xt_ints_on(mask);
}
/**
* @brief disable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be disabled
*/
static inline void intr_cntrl_ll_disable_interrupts(uint32_t mask)
{
xt_ints_off(mask);
}
/**
* @brief checks if given interrupt number has a valid handler
*
* @param intr interrupt number ranged from 0 to 31
* @param cpu cpu number ranged betweeen 0 to SOC_CPU_CORES_NUM - 1
* @return true for valid handler, false otherwise
*/
static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu)
{
return xt_int_has_handler(intr, cpu);
}
/**
* @brief sets interrupt handler and optional argument of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
* @param handler handler invoked when an interrupt occurs
* @param arg optional argument to pass to the handler
*/
static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
{
xt_set_interrupt_handler(intr, (xt_handler)handler, arg);
}
/**
* @brief Gets argument passed to handler of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
*
* @return argument used by handler of passed interrupt number
*/
static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr)
{
return xt_get_interrupt_handler_arg(intr);
}
/**
* @brief Disables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
* @return oldmask where to store old interrupts state
*/
static inline uint32_t intr_cntrl_ll_disable_int_mask(uint32_t newmask)
{
return xt_int_disable_mask(newmask);
}
/**
* @brief Enables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
*/
static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask)
{
xt_int_enable_mask(newmask);
}
/**
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
*
* @param intr interrupt number ranged from 0 to 31
*/
static inline void intr_cntrl_ll_edge_int_acknowledge (int intr)
{
xthal_set_intclear(1 << intr);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,487 @@
// 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"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_LL_GET_HW() &LEDC
/**
* @brief Set LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_set_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t slow_clk_sel){
uint32_t clk_sel_val = 0;
if (slow_clk_sel == LEDC_SLOW_CLK_APB) {
clk_sel_val = 1;
} else if (slow_clk_sel == LEDC_SLOW_CLK_RTC8M) {
clk_sel_val = 2;
} else if (slow_clk_sel == LEDC_SLOW_CLK_XTAL) {
clk_sel_val = 3;
}
hw->conf.apb_clk_sel = clk_sel_val;
}
/**
* @brief Get LEDC low speed timer clock
*
* @param hw Beginning address of the peripheral registers
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
static inline void ledc_ll_get_slow_clk_sel(ledc_dev_t *hw, ledc_slow_clk_sel_t *slow_clk_sel){
uint32_t clk_sel_val = hw->conf.apb_clk_sel;
if (clk_sel_val == 1) {
*slow_clk_sel = LEDC_SLOW_CLK_APB;
} else if (clk_sel_val == 2) {
*slow_clk_sel = LEDC_SLOW_CLK_RTC8M;
} else if (clk_sel_val == 3) {
*slow_clk_sel = LEDC_SLOW_CLK_XTAL;
}
}
/**
* @brief Update LEDC low speed timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_ls_timer_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
}
/**
* @brief Reset LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_rst(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
hw->timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
}
/**
* @brief Pause LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_pause(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
}
/**
* @brief Resume LEDC timer
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_timer_resume(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel){
hw->timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
}
/**
* @brief Set LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_set_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider){
hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider = clock_divider;
}
/**
* @brief Get LEDC timer clock divider
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_divider(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *clock_divider){
*clock_divider = hw->timer_group[speed_mode].timer[timer_sel].conf.clock_divider;
}
/**
* @brief Set LEDC timer clock source
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @return None
*/
static inline void ledc_ll_set_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t clk_src){
if (clk_src == LEDC_REF_TICK) {
//REF_TICK can only be used when APB is selected.
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 1;
hw->conf.apb_clk_sel = 1;
} else {
hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel = 0;
}
}
/**
* @brief Get LEDC timer clock source
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Pointer to accept the timer clock source
*
* @return None
*/
static inline void ledc_ll_get_clock_source(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, ledc_clk_src_t *clk_src){
if (hw->timer_group[speed_mode].timer[timer_sel].conf.tick_sel == 1) {
*clk_src = LEDC_REF_TICK;
} else {
*clk_src = LEDC_APB_CLK;
}
}
/**
* @brief Set LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t duty_resolution){
hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution = duty_resolution;
}
/**
* @brief Get LEDC duty resolution
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
*
* @return None
*/
static inline void ledc_ll_get_duty_resolution(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t *duty_resolution){
*duty_resolution = hw->timer_group[speed_mode].timer[timer_sel].conf.duty_resolution;
}
/**
* @brief Update channel configure when select low speed mode
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_ls_channel_update(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
hw->channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1;
}
/**
* @brief Get LEDC max duty
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param max_duty Pointer to accept the max duty
*
* @return None
*/
static inline void ledc_ll_get_max_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *max_duty){
uint32_t timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
*max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.duty_resolution));
}
/**
* @brief Set LEDC hpoint value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_set_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t hpoint_val){
hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
}
/**
* @brief Get LEDC hpoint value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
static inline void ledc_ll_get_hpoint(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *hpoint_val){
*hpoint_val = hw->channel_group[speed_mode].channel[channel_num].hpoint.hpoint;
}
/**
* @brief Set LEDC the integer part of duty value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
*
* @return None
*/
static inline void ledc_ll_set_duty_int_part(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_val){
hw->channel_group[speed_mode].channel[channel_num].duty.duty = duty_val << 4;
}
/**
* @brief Get LEDC duty value
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val Pointer to accept the LEDC duty value
*
* @return None
*/
static inline void ledc_ll_get_duty(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t *duty_val){
*duty_val = (hw->channel_group[speed_mode].channel[channel_num].duty_rd.duty_read >> 4);
}
/**
* @brief Set LEDC duty change direction
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction LEDC duty change direction, increase or decrease
*
* @return None
*/
static inline void ledc_ll_set_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc = duty_direction;
}
/**
* @brief Get LEDC duty change direction
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction Pointer to accept the LEDC duty change direction, increase or decrease
*
* @return None
*/
static inline void ledc_ll_get_duty_direction(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_duty_direction_t *duty_direction){
*duty_direction = hw->channel_group[speed_mode].channel[channel_num].conf1.duty_inc;
}
/**
* @brief Set the number of increased or decreased times
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_num The number of increased or decreased times
*
* @return None
*/
static inline void ledc_ll_set_duty_num(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_num){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_num = duty_num;
}
/**
* @brief Set the duty cycles of increase or decrease
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_cycle The duty cycles
*
* @return None
*/
static inline void ledc_ll_set_duty_cycle(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_cycle){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_cycle = duty_cycle;
}
/**
* @brief Set the step scale of increase or decrease
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_scale The step scale
*
* @return None
*/
static inline void ledc_ll_set_duty_scale(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t duty_scale){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_scale = duty_scale;
}
/**
* @brief Set the output enable
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param sig_out_en The output enable status
*
* @return None
*/
static inline void ledc_ll_set_sig_out_en(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool sig_out_en){
hw->channel_group[speed_mode].channel[channel_num].conf0.sig_out_en = sig_out_en;
}
/**
* @brief Set the duty start
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_start The duty start
*
* @return None
*/
static inline void ledc_ll_set_duty_start(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool duty_start){
hw->channel_group[speed_mode].channel[channel_num].conf1.duty_start = duty_start;
}
/**
* @brief Set output idle level
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param idle_level The output idle level
*
* @return None
*/
static inline void ledc_ll_set_idle_level(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, uint32_t idle_level){
hw->channel_group[speed_mode].channel[channel_num].conf0.idle_lv = idle_level & 0x1;
}
/**
* @brief Set fade end interrupt enable
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param fade_end_intr_en The fade end interrupt enable status
*
* @return None
*/
static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, bool fade_end_intr_en){
uint32_t value = hw->int_ena.val;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
hw->int_ena.val = fade_end_intr_en ? (value | BIT(int_en_base + channel_num)) : (value & (~(BIT(int_en_base + channel_num))));
}
/**
* @brief Get fade end interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param intr_status The fade end interrupt status
*
* @return None
*/
static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, uint32_t *intr_status){
uint32_t value = hw->int_st.val;
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
*intr_status = (value >> int_en_base) & 0xff;
}
/**
* @brief Clear fade end interrupt status
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
static inline void ledc_ll_clear_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num){
uint32_t int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S;
hw->int_clr.val = BIT(int_en_base + channel_num);
}
/**
* @brief Set timer index of the specified channel
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
static inline void ledc_ll_bind_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t timer_sel){
hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel = timer_sel;
}
/**
* @brief Get timer index of the specified channel
*
* @param hw Beginning address of the peripheral registers
* @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel Pointer to accept the LEDC timer index
*
* @return None
*/
static inline void ledc_ll_get_channel_timer(ledc_dev_t *hw, ledc_mode_t speed_mode, ledc_channel_t channel_num, ledc_timer_t *timer_sel){
*timer_sel = hw->channel_group[speed_mode].channel[channel_num].conf0.timer_sel;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,881 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* ========================================================================================
* === IRAM0 common
* ========================================================================================
*/
//IRAM0 interrupt status bitmasks
#define IRAM0_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1
#define IRAM0_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1
static inline void esp_memprot_iram0_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR);
}
static inline uint32_t esp_memprot_iram0_get_intr_source_num(void)
{
return ETS_PMS_PRO_IRAM0_ILG_INTR_SOURCE;
}
static inline void esp_memprot_iram0_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN);
}
}
static inline uint32_t esp_memprot_iram0_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_4_REG);
}
static inline uint32_t esp_memprot_iram0_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_5_REG);
}
static inline void esp_memprot_iram0_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_iram0_get_fault_reg();
*op_type = (uint32_t)status_bits & IRAM0_INTR_ST_OP_RW_BIT;
*op_subtype = (uint32_t)status_bits & IRAM0_INTR_ST_OP_TYPE_BIT;
}
static inline bool esp_memprot_iram0_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_INTR) > 0;
}
static inline uint32_t esp_memprot_iram0_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN);
}
static inline uint32_t esp_memprot_iram0_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_INTR);
}
static inline uint32_t esp_memprot_iram0_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR);
}
//resets automatically on CPU restart
static inline void esp_memprot_iram0_set_lock(void)
{
DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_0_REG, DPORT_PMS_PRO_IRAM0_LOCK);
}
static inline uint32_t esp_memprot_iram0_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_0_REG);
}
static inline uint32_t esp_memprot_iram0_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_0_REG, DPORT_PMS_PRO_IRAM0_LOCK);
}
/**
* ========================================================================================
* === IRAM0 SRAM
* ========================================================================================
*/
#define IRAM0_SRAM_ADDRESS_LOW 0x40020000
#define IRAM0_SRAM_ADDRESS_HIGH 0x4006FFFF
#define IRAM0_SRAM_TOTAL_UNI_BLOCKS 4
#define IRAM0_SRAM_UNI_BLOCK_0 0
#define IRAM0_SRAM_UNI_BLOCK_1 1
#define IRAM0_SRAM_UNI_BLOCK_2 2
#define IRAM0_SRAM_UNI_BLOCK_3 3
//unified management (SRAM blocks 0-3)
#define IRAM0_SRAM_UNI_BLOCK_0_LOW 0x40020000
#define IRAM0_SRAM_UNI_BLOCK_1_LOW 0x40022000
#define IRAM0_SRAM_UNI_BLOCK_2_LOW 0x40024000
#define IRAM0_SRAM_UNI_BLOCK_3_LOW 0x40026000
//split management (SRAM blocks 4-21)
#define IRAM0_SRAM_SPL_BLOCK_LOW 0x40028000 //block 4 low
#define IRAM0_SRAM_SPL_BLOCK_HIGH 0x4006FFFF //block 21 high
#define IRAM0_INTR_ST_FAULTADDR_M 0x003FFFFC //bits 21:6 in the reg, as well as in real address
#define IRAM0_SRAM_INTR_ST_FAULTADDR_HI 0x40000000 //high nonsignificant bits 31:22 of the faulting address - constant
static inline uint32_t *esp_memprot_iram0_sram_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_iram0_get_fault_reg();
return (uint32_t *)((status_bits & IRAM0_INTR_ST_FAULTADDR_M) | IRAM0_SRAM_INTR_ST_FAULTADDR_HI);
}
static inline bool esp_memprot_iram0_sram_is_intr_mine(void)
{
if (esp_memprot_iram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_iram0_sram_get_fault_address();
return (uint32_t)faulting_address >= IRAM0_SRAM_ADDRESS_LOW && (uint32_t)faulting_address <= IRAM0_SRAM_ADDRESS_HIGH;
}
return false;
}
//block 0-3
static inline void esp_memprot_iram0_sram_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm, bool exec_perm)
{
assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS);
uint32_t write_bit, read_bit, exec_bit;
switch (block) {
case IRAM0_SRAM_UNI_BLOCK_0:
write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W;
read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R;
exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F;
break;
case IRAM0_SRAM_UNI_BLOCK_1:
write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W;
read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R;
exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F;
break;
case IRAM0_SRAM_UNI_BLOCK_2:
write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W;
read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R;
exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F;
break;
case IRAM0_SRAM_UNI_BLOCK_3:
write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W;
read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R;
exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F;
break;
default:
abort();
}
if (write_perm) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, write_bit);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, write_bit);
}
if (read_perm) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, read_bit);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, read_bit);
}
if (exec_perm) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, exec_bit);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, exec_bit);
}
}
static inline uint32_t esp_memprot_iram0_sram_get_uni_block_read_bit(uint32_t block)
{
assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case IRAM0_SRAM_UNI_BLOCK_0:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_R);
case IRAM0_SRAM_UNI_BLOCK_1:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_R);
case IRAM0_SRAM_UNI_BLOCK_2:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_R);
case IRAM0_SRAM_UNI_BLOCK_3:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_R);
default:
abort();
}
}
static inline uint32_t esp_memprot_iram0_sram_get_uni_block_write_bit(uint32_t block)
{
assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case IRAM0_SRAM_UNI_BLOCK_0:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_W);
case IRAM0_SRAM_UNI_BLOCK_1:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_W);
case IRAM0_SRAM_UNI_BLOCK_2:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_W);
case IRAM0_SRAM_UNI_BLOCK_3:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_W);
default:
abort();
}
}
static inline uint32_t esp_memprot_iram0_sram_get_uni_block_exec_bit(uint32_t block)
{
assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case IRAM0_SRAM_UNI_BLOCK_0:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_F);
case IRAM0_SRAM_UNI_BLOCK_1:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_F);
case IRAM0_SRAM_UNI_BLOCK_2:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_F);
case IRAM0_SRAM_UNI_BLOCK_3:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_F);
default:
abort();
}
}
static inline void esp_memprot_iram0_sram_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit, uint32_t *exec_bit)
{
assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case IRAM0_SRAM_UNI_BLOCK_0:
*write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W;
*read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R;
*exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F;
break;
case IRAM0_SRAM_UNI_BLOCK_1:
*write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W;
*read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R;
*exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F;
break;
case IRAM0_SRAM_UNI_BLOCK_2:
*write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W;
*read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R;
*exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F;
break;
case IRAM0_SRAM_UNI_BLOCK_3:
*write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W;
*read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R;
*exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F;
break;
default:
abort();
}
}
static inline uint32_t esp_memprot_iram0_sram_get_perm_uni_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_1_REG);
}
static inline uint32_t esp_memprot_iram0_sram_get_perm_split_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_2_REG);
}
static inline void esp_memprot_iram0_sram_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
assert(addr <= IRAM0_SRAM_SPL_BLOCK_HIGH);
//find possible split.address in low region blocks
int uni_blocks_low = -1;
if (addr >= IRAM0_SRAM_UNI_BLOCK_0_LOW) {
uni_blocks_low++;
}
if (addr >= IRAM0_SRAM_UNI_BLOCK_1_LOW) {
uni_blocks_low++;
}
if (addr >= IRAM0_SRAM_UNI_BLOCK_2_LOW) {
uni_blocks_low++;
}
if (addr >= IRAM0_SRAM_UNI_BLOCK_3_LOW) {
uni_blocks_low++;
}
//unified mgmt settings per block (bits W/R/X: [11:9] bl3, [8:6] bl2, [5:3] bl1, [2:0] bl0)
uint32_t write_bit, read_bit, exec_bit;
uint32_t uni_block_perm = 0;
for (int x = 0; x < IRAM0_SRAM_TOTAL_UNI_BLOCKS; x++) {
esp_memprot_iram0_sram_get_uni_block_sgnf_bits(x, &write_bit, &read_bit, &exec_bit);
if (x <= uni_blocks_low) {
if (lw) {
uni_block_perm |= write_bit;
}
if (lr) {
uni_block_perm |= read_bit;
}
if (lx) {
uni_block_perm |= exec_bit;
}
} else {
if (hw) {
uni_block_perm |= write_bit;
}
if (hr) {
uni_block_perm |= read_bit;
}
if (hx) {
uni_block_perm |= exec_bit;
}
}
}
//if splt.ddr not set yet, do required normalization to make the addr writeble into splt.mgmt cfg register
uint32_t reg_split_addr = 0;
if (addr >= IRAM0_SRAM_SPL_BLOCK_LOW) {
//[16:0]
reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_M;
}
//prepare high & low permission mask (bits: [22:20] high range, [19:17] low range)
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_F;
}
//write IRAM SRAM uni & splt cfg. registers
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_1_REG, uni_block_perm);
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_2_REG, (uint32_t)(reg_split_addr | permission_mask));
}
static inline void esp_memprot_iram0_sram_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F);
}
static inline void esp_memprot_iram0_sram_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_iram0_sram_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_iram0_sram_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F, hx ? 1 : 0);
}
/**
* ========================================================================================
* === IRAM0 RTC FAST
* ========================================================================================
*/
#define IRAM0_RTCFAST_ADDRESS_LOW 0x40070000
#define IRAM0_RTCFAST_ADDRESS_HIGH 0x40071FFF
#define IRAM0_RTCFAST_INTR_ST_FAULTADDR_HI 0x40070000 //RTCFAST faulting address high bits (31:22, constant)
static inline uint32_t *esp_memprot_iram0_rtcfast_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_iram0_get_fault_reg();
return (uint32_t *)((status_bits & IRAM0_INTR_ST_FAULTADDR_M) | IRAM0_RTCFAST_INTR_ST_FAULTADDR_HI);
}
static inline bool esp_memprot_iram0_rtcfast_is_intr_mine(void)
{
if (esp_memprot_iram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_iram0_rtcfast_get_fault_address();
return (uint32_t)faulting_address >= IRAM0_RTCFAST_ADDRESS_LOW && (uint32_t)faulting_address <= IRAM0_RTCFAST_ADDRESS_HIGH;
}
return false;
}
static inline uint32_t esp_memprot_iram0_rtcfast_get_perm_split_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_3_REG);
}
static inline void esp_memprot_iram0_rtcfast_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
//if splt.ddr not set yet, do required normalization to make the addr writeble into splt.mgmt cfg register
uint32_t reg_split_addr = 0;
//[10:0]
reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_IRAM0_RTCFAST_SPLTADDR_M;
//prepare high & low permission mask (bits: [16:14] high range, [13:11] low range)
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_F;
}
//write IRAM0 RTCFAST cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_3_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_iram0_rtcfast_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_F);
}
static inline void esp_memprot_iram0_rtcfast_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_iram0_rtcfast_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_iram0_rtcfast_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_F, hx ? 1 : 0);
}
/**
* ========================================================================================
* === DRAM0 common
* ========================================================================================
*/
//DRAM0 interrupt status bitmasks
#define DRAM0_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg)
#define DRAM0_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address)
#define DRAM0_INTR_ST_OP_RW_BIT BIT(4) //read: 0, write: 1
#define DRAM0_INTR_ST_OP_ATOMIC_BIT BIT(5) //non-atomic: 0, atomic: 1
static inline uint32_t esp_memprot_dram0_get_intr_source_num(void)
{
return ETS_PMS_PRO_DRAM0_ILG_INTR_SOURCE;
}
static inline void esp_memprot_dram0_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN);
}
}
static inline bool esp_memprot_dram0_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_INTR) > 0;
}
static inline void esp_memprot_dram0_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR);
}
static inline uint32_t esp_memprot_dram0_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN);
}
static inline uint32_t esp_memprot_dram0_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_INTR);
}
static inline uint32_t esp_memprot_dram0_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR);
}
//lock resets automatically on CPU restart
static inline void esp_memprot_dram0_set_lock(void)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK);
}
static inline uint32_t esp_memprot_dram0_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_0_REG);
}
static inline uint32_t esp_memprot_dram0_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK);
}
static inline uint32_t esp_memprot_dram0_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_3_REG);
}
static inline uint32_t esp_memprot_dram0_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_4_REG);
}
static inline void esp_memprot_dram0_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_dram0_get_fault_reg();
*op_type = status_bits & DRAM0_INTR_ST_OP_RW_BIT;
*op_subtype = status_bits & DRAM0_INTR_ST_OP_ATOMIC_BIT;
}
/**
* ========================================================================================
* === DRAM0 SRAM
* ========================================================================================
*/
#define DRAM0_SRAM_ADDRESS_LOW 0x3FFB0000
#define DRAM0_SRAM_ADDRESS_HIGH 0x3FFFFFFF
#define DRAM0_SRAM_TOTAL_UNI_BLOCKS 4
#define DRAM0_SRAM_UNI_BLOCK_0 0
#define DRAM0_SRAM_UNI_BLOCK_1 1
#define DRAM0_SRAM_UNI_BLOCK_2 2
#define DRAM0_SRAM_UNI_BLOCK_3 3
//unified management (SRAM blocks 0-3)
#define DRAM0_SRAM_UNI_BLOCK_0_LOW 0x3FFB0000
#define DRAM0_SRAM_UNI_BLOCK_1_LOW 0x3FFB2000
#define DRAM0_SRAM_UNI_BLOCK_2_LOW 0x3FFB4000
#define DRAM0_SRAM_UNI_BLOCK_3_LOW 0x3FFB6000
//split management (SRAM blocks 4-21)
#define DRAM0_SRAM_SPL_BLOCK_HIGH 0x3FFFFFFF //block 21 high
#define DRAM0_SRAM_INTR_ST_FAULTADDR_HI 0x3FF00000 //SRAM high bits 31:22 of the faulting address - constant
static inline uint32_t *esp_memprot_dram0_sram_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_dram0_get_fault_reg();
return (uint32_t *)(((status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S) | DRAM0_SRAM_INTR_ST_FAULTADDR_HI);
}
static inline bool esp_memprot_dram0_sram_is_intr_mine(void)
{
if (esp_memprot_dram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_dram0_sram_get_fault_address();
return (uint32_t)faulting_address >= DRAM0_SRAM_ADDRESS_LOW && (uint32_t)faulting_address <= DRAM0_SRAM_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_dram0_sram_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit)
{
assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case DRAM0_SRAM_UNI_BLOCK_0:
*write_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_W;
*read_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_R;
break;
case DRAM0_SRAM_UNI_BLOCK_1:
*write_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_W;
*read_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_R;
break;
case DRAM0_SRAM_UNI_BLOCK_2:
*write_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_W;
*read_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_R;
break;
case DRAM0_SRAM_UNI_BLOCK_3:
*write_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_W;
*read_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_R;
break;
default:
abort();
}
}
static inline void esp_memprot_dram0_sram_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm)
{
assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS);
uint32_t write_bit, read_bit;
esp_memprot_dram0_sram_get_uni_block_sgnf_bits(block, &write_bit, &read_bit);
if (write_perm) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, write_bit);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, write_bit);
}
if (read_perm) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, read_bit);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, read_bit);
}
}
static inline uint32_t esp_memprot_dram0_sram_get_uni_block_read_bit(uint32_t block)
{
assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case DRAM0_SRAM_UNI_BLOCK_0:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_R);
case DRAM0_SRAM_UNI_BLOCK_1:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_R);
case DRAM0_SRAM_UNI_BLOCK_2:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_R);
case DRAM0_SRAM_UNI_BLOCK_3:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_R);
default:
abort();
}
}
static inline uint32_t esp_memprot_dram0_sram_get_uni_block_write_bit(uint32_t block)
{
assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS);
switch (block) {
case DRAM0_SRAM_UNI_BLOCK_0:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_W);
case DRAM0_SRAM_UNI_BLOCK_1:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_W);
case DRAM0_SRAM_UNI_BLOCK_2:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_W);
case DRAM0_SRAM_UNI_BLOCK_3:
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_W);
default:
abort();
}
}
//DRAM0 has both unified blocks and split address configured in 1 register
static inline uint32_t esp_memprot_dram0_sram_get_perm_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG);
}
static inline void esp_memprot_dram0_sram_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
{
uint32_t addr = (uint32_t)split_addr;
//low boundary check provided by LD script. see comment in esp_memprot_iram0_sram_set_prot()
assert( addr <= DRAM0_SRAM_SPL_BLOCK_HIGH );
//set low region
int uni_blocks_low = -1;
if (addr >= DRAM0_SRAM_UNI_BLOCK_0_LOW) {
uni_blocks_low++;
}
if (addr >= DRAM0_SRAM_UNI_BLOCK_1_LOW) {
uni_blocks_low++;
}
if (addr >= DRAM0_SRAM_UNI_BLOCK_2_LOW) {
uni_blocks_low++;
}
if (addr >= DRAM0_SRAM_UNI_BLOCK_3_LOW) {
uni_blocks_low++;
}
//set unified mgmt region
uint32_t write_bit, read_bit, uni_block_perm = 0;
for (int x = 0; x < DRAM0_SRAM_TOTAL_UNI_BLOCKS; x++) {
esp_memprot_dram0_sram_get_uni_block_sgnf_bits(x, &write_bit, &read_bit);
if (x <= uni_blocks_low) {
if (lw) {
uni_block_perm |= write_bit;
}
if (lr) {
uni_block_perm |= read_bit;
}
} else {
if (hw) {
uni_block_perm |= write_bit;
}
if (hr) {
uni_block_perm |= read_bit;
}
}
}
//[24:8]
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr = (reg_split_addr & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_V) << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_L_R;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_H_R;
}
//write DRAM0 SRAM cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG, reg_split_addr | permission_mask | uni_block_perm);
}
static inline void esp_memprot_dram0_sram_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R);
}
static inline void esp_memprot_dram0_sram_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_dram0_sram_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W, hw ? 1 : 0);
}
/**
* ========================================================================================
* === DRAM0 RTC FAST
* ========================================================================================
*/
#define DRAM0_RTCFAST_ADDRESS_LOW 0x3FF9E000
#define DRAM0_RTCFAST_ADDRESS_HIGH 0x3FF9FFFF
#define DRAM0_RTCFAST_INTR_ST_FAULTADDR_HI 0x3FF00000 //RTCFAST high bits 31:22 of the faulting address - constant
static inline uint32_t *esp_memprot_dram0_rtcfast_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_dram0_get_fault_reg();
return (uint32_t *)(((status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S) | DRAM0_RTCFAST_INTR_ST_FAULTADDR_HI);
}
static inline bool esp_memprot_dram0_rtcfast_is_intr_mine(void)
{
if (esp_memprot_dram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_dram0_rtcfast_get_fault_address();
return (uint32_t)faulting_address >= DRAM0_RTCFAST_ADDRESS_LOW && (uint32_t)faulting_address <= DRAM0_RTCFAST_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_dram0_rtcfast_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
{
uint32_t addr = (uint32_t)split_addr;
//[10:0]
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_DRAM0_RTCFAST_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_L_R;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_H_R;
}
//write DRAM0 RTC FAST cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_2_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_dram0_rtcfast_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_R);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_R);
}
static inline uint32_t esp_memprot_dram0_rtcfast_get_perm_split_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_2_REG);
}
static inline void esp_memprot_dram0_rtcfast_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_dram0_rtcfast_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_W, hw ? 1 : 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,453 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define RTCSLOW_MEMORY_SIZE 0x00002000
/**
* ========================================================================================
* === PeriBus1 common
* ========================================================================================
*/
//PeriBus1 interrupt status bitmasks
#define PERI1_INTR_ST_OP_TYPE_BIT BIT(4) //0: non-atomic, 1: atomic
#define PERI1_INTR_ST_OP_HIGH_BITS BIT(5) //0: high bits = unchanged, 1: high bits = 0x03F40000
#define PERI1_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg)
#define PERI1_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address)
static inline void esp_memprot_peri1_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR);
}
static inline uint32_t esp_memprot_peri1_get_intr_source_num(void)
{
return ETS_PMS_PRO_DPORT_ILG_INTR_SOURCE;
}
static inline void esp_memprot_peri1_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
}
}
static inline uint32_t esp_memprot_peri1_get_ctrl_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_6_REG);
}
static inline uint32_t esp_memprot_peri1_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_7_REG);
}
static inline void esp_memprot_peri1_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_peri1_get_fault_reg();
//*op_type = (uint32_t)status_bits & PERI1_INTR_ST_OP_RW_BIT;
*op_type = 0;
//! DPORT_PMS_PRO_DPORT_7_REG is missing op_type bit
*op_subtype = (uint32_t)status_bits & PERI1_INTR_ST_OP_TYPE_BIT;
}
static inline bool esp_memprot_peri1_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_7_REG, DPORT_PMS_PRO_DPORT_ILG_INTR) > 0;
}
static inline uint32_t esp_memprot_peri1_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN);
}
static inline uint32_t esp_memprot_peri1_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_INTR);
}
static inline uint32_t esp_memprot_peri1_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR);
}
static inline uint32_t esp_memprot_peri1_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG);
}
//resets automatically on CPU restart
static inline void esp_memprot_peri1_set_lock(void)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK);
}
static inline uint32_t esp_memprot_peri1_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK);
}
/**
* ========================================================================================
* === PeriBus1 RTC SLOW
* ========================================================================================
*/
#define PERI1_RTCSLOW_ADDRESS_BASE 0x3F421000
#define PERI1_RTCSLOW_ADDRESS_LOW PERI1_RTCSLOW_ADDRESS_BASE
#define PERI1_RTCSLOW_ADDRESS_HIGH PERI1_RTCSLOW_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
#define PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 0x3F400000
static inline uint32_t *esp_memprot_peri1_rtcslow_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_peri1_get_fault_reg();
uint32_t fault_address = (status_bits & PERI1_INTR_ST_FAULTADDR_M) >> PERI1_INTR_ST_FAULTADDR_S;
uint32_t high_bits = (status_bits & PERI1_INTR_ST_OP_HIGH_BITS) ? PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 : 0;
return (uint32_t *)(fault_address | high_bits);
}
static inline bool esp_memprot_peri1_rtcslow_is_intr_mine(void)
{
if (esp_memprot_dram0_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri1_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI1_RTCSLOW_ADDRESS_LOW && (uint32_t)faulting_address <= PERI1_RTCSLOW_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri1_rtcslow_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_DPORT_RTCSLOW_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_R;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_R;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri1_rtcslow_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R);
}
static inline void esp_memprot_peri1_rtcslow_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri1_rtcslow_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W, hw ? 1 : 0);
}
static inline uint32_t esp_memprot_peri1_rtcslow_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG);
}
/**
* ========================================================================================
* === PeriBus2 common
* ========================================================================================
*/
//PeriBus2 interrupt status bitmasks
#define PERI2_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1
#define PERI2_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1
#define PERI2_INTR_ST_FAULTADDR_M 0xFFFFFFFC //(bits 31:2 in the reg)
static inline void esp_memprot_peri2_clear_intr(void)
{
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR);
}
static inline uint32_t esp_memprot_peri2_get_intr_source_num(void)
{
return ETS_PMS_PRO_AHB_ILG_INTR_SOURCE;
}
static inline void esp_memprot_peri2_intr_ena(bool enable)
{
if (enable) {
DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
}
}
static inline uint32_t esp_memprot_peri2_get_ctrl_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_3_REG);
}
static inline uint32_t esp_memprot_peri2_get_fault_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_4_REG);
}
static inline void esp_memprot_peri2_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype)
{
uint32_t status_bits = esp_memprot_peri2_get_fault_reg();
*op_type = (uint32_t)status_bits & PERI2_INTR_ST_OP_RW_BIT;
*op_subtype = (uint32_t)status_bits & PERI2_INTR_ST_OP_TYPE_BIT;
}
static inline bool esp_memprot_peri2_is_assoc_intr(void)
{
return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR) > 0;
}
static inline uint32_t esp_memprot_peri2_get_intr_ena_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN);
}
static inline uint32_t esp_memprot_peri2_get_intr_on_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR);
}
static inline uint32_t esp_memprot_peri2_get_intr_clr_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR);
}
static inline uint32_t esp_memprot_peri2_get_lock_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_0_REG);
}
//resets automatically on CPU restart
static inline void esp_memprot_peri2_set_lock(void)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK);
}
static inline uint32_t esp_memprot_peri2_get_lock_bit(void)
{
return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK);
}
static inline uint32_t *esp_memprot_peri2_rtcslow_get_fault_address(void)
{
uint32_t status_bits = esp_memprot_peri2_get_fault_reg();
return (uint32_t *)(status_bits & PERI2_INTR_ST_FAULTADDR_M);
}
/**
* ========================================================================================
* === PeriBus2 RTC SLOW 0 (AHB0)
* ========================================================================================
*/
#define PERI2_RTCSLOW_0_ADDRESS_BASE 0x50000000
#define PERI2_RTCSLOW_0_ADDRESS_LOW PERI2_RTCSLOW_0_ADDRESS_BASE
#define PERI2_RTCSLOW_0_ADDRESS_HIGH PERI2_RTCSLOW_0_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
static inline bool esp_memprot_peri2_rtcslow_0_is_intr_mine(void)
{
if (esp_memprot_peri2_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI2_RTCSLOW_0_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_0_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri2_rtcslow_0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_0_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_1_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri2_rtcslow_0_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F);
}
static inline void esp_memprot_peri2_rtcslow_0_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_0_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_0_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F, hx ? 1 : 0);
}
static inline uint32_t esp_memprot_peri2_rtcslow_0_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG);
}
/**
* ========================================================================================
* === PeriBus2 RTC SLOW 1 (AHB1)
* ========================================================================================
*/
#define PERI2_RTCSLOW_1_ADDRESS_BASE 0x60021000
#define PERI2_RTCSLOW_1_ADDRESS_LOW PERI2_RTCSLOW_1_ADDRESS_BASE
#define PERI2_RTCSLOW_1_ADDRESS_HIGH PERI2_RTCSLOW_1_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE
static inline bool esp_memprot_peri2_rtcslow_1_is_intr_mine(void)
{
if (esp_memprot_peri2_is_assoc_intr()) {
uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address();
return (uint32_t)faulting_address >= PERI2_RTCSLOW_1_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_1_ADDRESS_HIGH;
}
return false;
}
static inline void esp_memprot_peri2_rtcslow_1_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
{
uint32_t addr = (uint32_t)split_addr;
//check split address is WORD aligned
uint32_t reg_split_addr = addr >> 2;
assert(addr == (reg_split_addr << 2));
reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_1_SPLTADDR_M;
//prepare high & low permission mask
uint32_t permission_mask = 0;
if (lw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W;
}
if (lr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R;
}
if (lx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F;
}
if (hw) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W;
}
if (hr) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R;
}
if (hx) {
permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F;
}
//write PERIBUS1 RTC SLOW cfg register
DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_2_REG, reg_split_addr | permission_mask);
}
static inline void esp_memprot_peri2_rtcslow_1_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
{
*lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W);
*lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R);
*lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F);
*hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W);
*hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R);
*hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F);
}
static inline void esp_memprot_peri2_rtcslow_1_set_read_perm(bool lr, bool hr)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R, lr ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R, hr ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_1_set_write_perm(bool lw, bool hw)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W, lw ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W, hw ? 1 : 0);
}
static inline void esp_memprot_peri2_rtcslow_1_set_exec_perm(bool lx, bool hx)
{
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F, lx ? 1 : 0);
DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F, hx ? 1 : 0);
}
static inline uint32_t esp_memprot_peri2_rtcslow_1_get_conf_reg(void)
{
return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_2_REG);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,62 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include "soc/soc_caps.h"
#include "xt_instr_macros.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline uint32_t mpu_ll_id_to_addr(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

View File

@@ -0,0 +1,264 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "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
*
* Locking the MWDT will prevent any of the MWDT's registers from being modified
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_write_protect_enable(timg_dev_t *hw)
{
hw->wdt_wprotect = 0;
}
/**
* @brief Disable write protection of the MWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_write_protect_disable(timg_dev_t *hw)
{
hw->wdt_wprotect = TIMG_WDT_WKEY_VALUE;
}
/**
* @brief Clear the MWDT interrupt status.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void mwdt_ll_clear_intr_status(timg_dev_t* hw)
{
hw->int_clr.wdt = 1;
}
/**
* @brief Set the interrupt enable bit for the MWDT interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param enable Whether to enable the MWDT interrupt
*/
FORCE_INLINE_ATTR void mwdt_ll_set_intr_enable(timg_dev_t* hw, bool enable)
{
hw->int_ena.wdt = (enable) ? 1 : 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,346 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The LL layer for ESP32-S2 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 channel edge 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
*/
static inline void pcnt_ll_set_edge_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)
{
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;
} else {
conf0_reg.ch1_pos_mode = pos_mode;
conf0_reg.ch1_neg_mode = neg_mode;
}
hw->conf_unit[unit].conf0 = conf0_reg;
}
/**
* @brief Set PCNT channel level mode
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @param channel PCNT channel number
* @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_level_mode(pcnt_dev_t *hw, pcnt_unit_t unit, pcnt_channel_t channel, 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_hctrl_mode = hctrl_mode;
conf0_reg.ch0_lctrl_mode = lctrl_mode;
} else {
conf0_reg.ch1_hctrl_mode = hctrl_mode;
conf0_reg.ch1_lctrl_mode = lctrl_mode;
}
hw->conf_unit[unit].conf0 = conf0_reg;
}
/**
* @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)
{
pcnt_ll_set_edge_mode(hw, unit, channel, pos_mode, neg_mode);
pcnt_ll_set_level_mode(hw, unit, channel, hctrl_mode, lctrl_mode);
}
/**
* @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_PULSE_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 Get PCNT event status
*
* @param hw Peripheral PCNT hardware instance address.
* @param unit PCNT unit number
* @return event status word
*/
static inline uint32_t pcnt_ll_get_event_status(pcnt_dev_t *hw, pcnt_unit_t unit)
{
return hw->status_unit[unit].val;
}
/**
* @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

View File

@@ -0,0 +1,480 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/rmt_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RMT_LL_HW_BASE (&RMT)
#define RMT_LL_MEM_BASE (&RMTMEM)
// Note: TX and RX channel number are all index from zero in the LL driver
// i.e. tx_channel belongs to [0,3], and rx_channel belongs to [0,3]
static inline void rmt_ll_enable_drive_clock(rmt_dev_t *dev, bool enable)
{
dev->apb_conf.clk_en = enable; // register clock gating
dev->apb_conf.mem_clk_force_on = enable; // memory clock gating
}
static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable)
{
dev->apb_conf.mem_force_pu = !enable;
dev->apb_conf.mem_force_pd = enable;
}
static inline bool rmt_ll_is_mem_power_down(rmt_dev_t *dev)
{
// the RTC domain can also power down RMT memory
// so it's probably not enough to detect whether it's powered down or not
// mem_force_pd has higher priority than mem_force_pu
return (dev->apb_conf.mem_force_pd) || !(dev->apb_conf.mem_force_pu);
}
static inline void rmt_ll_enable_mem_access(rmt_dev_t *dev, bool enable)
{
dev->apb_conf.fifo_mask = enable;
}
static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, uint8_t src, uint8_t div_num, uint8_t div_a, uint8_t div_b)
{
dev->conf_ch[channel].conf1.ref_always_on = src;
}
static inline uint32_t rmt_ll_get_group_clock_src(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.ref_always_on;
}
static inline void rmt_ll_tx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
dev->ref_cnt_rst.val |= (1 << channel);
}
static inline void rmt_ll_tx_reset_channels_clock_div(rmt_dev_t *dev, uint32_t channel_mask)
{
dev->ref_cnt_rst.val |= channel_mask;
}
static inline void rmt_ll_rx_reset_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
dev->ref_cnt_rst.val |= (1 << channel);
}
static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->conf_ch[channel].conf1.mem_rd_rst = 1;
dev->conf_ch[channel].conf1.mem_rd_rst = 0;
}
static inline void rmt_ll_rx_reset_pointer(rmt_dev_t *dev, uint32_t channel)
{
dev->conf_ch[channel].conf1.mem_wr_rst = 1;
dev->conf_ch[channel].conf1.mem_wr_rst = 0;
}
static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
{
dev->conf_ch[channel].conf1.tx_start = 1;
}
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
{
dev->conf_ch[channel].conf1.tx_stop = 1;
}
static inline void rmt_ll_rx_enable(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf1.rx_en = enable;
}
static inline void rmt_ll_tx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->conf_ch[channel].conf0.mem_size = block_num;
}
static inline void rmt_ll_rx_set_mem_blocks(rmt_dev_t *dev, uint32_t channel, uint8_t block_num)
{
dev->conf_ch[channel].conf0.mem_size = block_num;
}
static inline uint32_t rmt_ll_tx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf0.mem_size;
}
static inline uint32_t rmt_ll_rx_get_mem_blocks(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf0.mem_size;
}
static inline void rmt_ll_tx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
dev->conf_ch[channel].conf0.div_cnt = div;
}
static inline void rmt_ll_rx_set_channel_clock_div(rmt_dev_t *dev, uint32_t channel, uint32_t div)
{
dev->conf_ch[channel].conf0.div_cnt = div;
}
static inline uint32_t rmt_ll_tx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = dev->conf_ch[channel].conf0.div_cnt;
return div == 0 ? 256 : div;
}
static inline uint32_t rmt_ll_rx_get_channel_clock_div(rmt_dev_t *dev, uint32_t channel)
{
uint32_t div = dev->conf_ch[channel].conf0.div_cnt;
return div == 0 ? 256 : div;
}
static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->apb_conf.mem_tx_wrap_en = enable;
}
static inline void rmt_ll_rx_set_idle_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
{
dev->conf_ch[channel].conf0.idle_thres = thres;
}
static inline uint32_t rmt_ll_rx_get_idle_thres(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf0.idle_thres;
}
static inline void rmt_ll_rx_set_mem_owner(rmt_dev_t *dev, uint32_t channel, uint8_t owner)
{
dev->conf_ch[channel].conf1.mem_owner = owner;
}
static inline uint32_t rmt_ll_rx_get_mem_owner(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.mem_owner;
}
static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf1.tx_conti_mode = enable;
}
static inline bool rmt_ll_is_tx_loop_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.tx_conti_mode;
}
static inline void rmt_ll_tx_set_loop_count(rmt_dev_t *dev, uint32_t channel, uint32_t count)
{
dev->tx_lim_ch[channel].tx_loop_num = count;
}
static inline void rmt_ll_tx_reset_loop(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_lim_ch[channel].loop_count_reset = 1;
dev->tx_lim_ch[channel].loop_count_reset = 0;
}
static inline void rmt_ll_tx_enable_loop_count(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->tx_lim_ch[channel].tx_loop_cnt_en = enable;
}
static inline void rmt_ll_tx_enable_sync(rmt_dev_t *dev, bool enable)
{
dev->tx_sim.en = enable;
}
static inline void rmt_ll_tx_add_to_sync_group(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_sim.val |= 1 << channel;
}
static inline void rmt_ll_tx_remove_from_sync_group(rmt_dev_t *dev, uint32_t channel)
{
dev->tx_sim.val &= ~(1 << channel);
}
static inline void rmt_ll_rx_enable_filter(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf1.rx_filter_en = enable;
}
static inline void rmt_ll_rx_set_filter_thres(rmt_dev_t *dev, uint32_t channel, uint32_t thres)
{
dev->conf_ch[channel].conf1.rx_filter_thres = thres;
}
static inline void rmt_ll_tx_enable_idle(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf1.idle_out_en = enable;
}
static inline bool rmt_ll_is_tx_idle_enabled(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.idle_out_en;
}
static inline void rmt_ll_tx_set_idle_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->conf_ch[channel].conf1.idle_out_lv = level;
}
static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel)
{
return dev->conf_ch[channel].conf1.idle_out_lv;
}
static inline uint32_t rmt_ll_rx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->status_ch[channel].val;
}
static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel)
{
return dev->status_ch[channel].val;
}
static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->tx_lim_ch[channel].limit = limit;
}
static inline void rmt_ll_rx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit)
{
dev->tx_lim_ch[channel].rx_lim = limit;
}
static inline uint32_t rmt_ll_rx_get_limit(rmt_dev_t *dev, uint32_t channel)
{
return dev->tx_lim_ch[channel].rx_lim;
}
static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel * 3));
dev->int_ena.val |= (enable << (channel * 3));
}
static inline void rmt_ll_enable_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel * 3 + 1));
dev->int_ena.val |= (enable << (channel * 3 + 1));
}
static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel * 3 + 2));
dev->int_ena.val |= (enable << (channel * 3 + 2));
}
static inline void rmt_ll_enable_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel * 3 + 2));
dev->int_ena.val |= (enable << (channel * 3 + 2));
}
static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel + 12));
dev->int_ena.val |= (enable << (channel + 12));
}
static inline void rmt_ll_enable_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel + 16));
dev->int_ena.val |= (enable << (channel + 16));
}
static inline void rmt_ll_enable_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->int_ena.val &= ~(1 << (channel + 20));
dev->int_ena.val |= (enable << (channel + 20));
}
static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel * 3));
}
static inline void rmt_ll_clear_rx_end_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel * 3 + 1));
}
static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel * 3 + 2));
}
static inline void rmt_ll_clear_rx_err_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel * 3 + 2));
}
static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 12));
}
static inline void rmt_ll_clear_tx_loop_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 16));
}
static inline void rmt_ll_clear_rx_thres_interrupt(rmt_dev_t *dev, uint32_t channel)
{
dev->int_clr.val = (1 << (channel + 20));
}
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);
}
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);
}
static inline uint32_t rmt_ll_get_tx_err_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x04) >> 2) | ((status & 0x20) >> 4) | ((status & 0x100) >> 6) | ((status & 0x800) >> 8);
}
static inline uint32_t rmt_ll_get_rx_err_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return ((status & 0x04) >> 2) | ((status & 0x20) >> 4) | ((status & 0x100) >> 6) | ((status & 0x800) >> 8);
}
static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return (status & 0xF000) >> 12;
}
static inline uint32_t rmt_ll_get_tx_loop_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return (status & 0xF0000) >> 16;
}
static inline uint32_t rmt_ll_get_rx_thres_interrupt_status(rmt_dev_t *dev)
{
uint32_t status = dev->int_st.val;
return (status & 0xF00000) >> 20;
}
static inline void rmt_ll_tx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
// In case the compiler optimise a 32bit instruction (e.g. s32i) into two 16bit instruction (e.g. s16i, which is not allowed to access a register)
// We take care of the "read-modify-write" procedure by ourselves.
typeof(dev->carrier_duty_ch[0]) reg;
reg.high = high_ticks;
reg.low = low_ticks;
dev->carrier_duty_ch[channel].val = reg.val;
}
static inline void rmt_ll_rx_set_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t high_ticks, uint32_t low_ticks)
{
typeof(dev->ch_rx_carrier_rm[0]) reg;
reg.carrier_high_thres_ch = high_ticks;
reg.carrier_low_thres_ch = low_ticks;
dev->ch_rx_carrier_rm[channel].val = reg.val;
}
static inline void rmt_ll_tx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks)
{
*high_ticks = dev->carrier_duty_ch[channel].high;
*low_ticks = dev->carrier_duty_ch[channel].low;
}
static inline void rmt_ll_rx_get_carrier_high_low_ticks(rmt_dev_t *dev, uint32_t channel, uint32_t *high_ticks, uint32_t *low_ticks)
{
*high_ticks = dev->ch_rx_carrier_rm[channel].carrier_high_thres_ch;
*low_ticks = dev->ch_rx_carrier_rm[channel].carrier_low_thres_ch;
}
static inline void rmt_ll_tx_enable_carrier_modulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf0.carrier_en = enable;
}
static inline void rmt_ll_rx_enable_carrier_demodulation(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf0.carrier_en = enable;
}
static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->conf_ch[channel].conf0.carrier_out_lv = level;
}
static inline void rmt_ll_rx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, uint8_t level)
{
dev->conf_ch[channel].conf0.carrier_out_lv = level;
}
// set true, enable carrier in all RMT state (idle, reading, sending)
// set false, enable carrier only in sending state (i.e. there're effective data in RAM to be sent)
static inline void rmt_ll_tx_set_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf0.carrier_eff_en = !enable;
}
//Writes items to the specified TX channel memory with the given offset and writen length.
//the caller should ensure that (length + off) <= (memory block * SOC_RMT_MEM_WORDS_PER_CHANNEL)
static inline void rmt_ll_write_memory(rmt_mem_t *mem, uint32_t channel, const rmt_item32_t *data, uint32_t length, uint32_t off)
{
for (uint32_t i = 0; i < length; i++) {
mem->chan[channel].data32[i + off].val = data[i].val;
}
}
static inline void rmt_ll_rx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable)
{
dev->conf_ch[channel].conf1.chk_rx_carrier_en = enable;
}
static inline void rmt_ll_config_update(rmt_dev_t *dev, uint32_t channel)
{
}
/************************************************************************************************
* Following Low Level APIs only used for backward compatible, will be deprecated in the IDF v5.0
***********************************************************************************************/
static inline void rmt_ll_set_intr_enable_mask(uint32_t mask)
{
RMT.int_ena.val |= mask;
}
static inline void rmt_ll_clr_intr_enable_mask(uint32_t mask)
{
RMT.int_ena.val &= (~mask);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,58 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void rtc_cntl_ll_set_wakeup_timer(uint64_t t)
{
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER0_REG, t & UINT32_MAX);
WRITE_PERI_REG(RTC_CNTL_SLP_TIMER1_REG, t >> 32);
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG, RTC_CNTL_MAIN_TIMER_INT_CLR_M);
SET_PERI_REG_MASK(RTC_CNTL_SLP_TIMER1_REG, RTC_CNTL_MAIN_TIMER_ALARM_EN_M);
}
static inline uint32_t rtc_cntl_ll_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_ext1_clear_wakeup_pins(void)
{
REG_SET_BIT(RTC_CNTL_EXT_WAKEUP1_REG, RTC_CNTL_EXT_WAKEUP1_STATUS_CLR);
}
static inline void rtc_cntl_ll_ulp_wakeup_enable(void)
{
SET_PERI_REG_BITS(RTC_CNTL_STATE0_REG, RTC_CNTL_WAKEUP_ENA_V, 0x800, RTC_CNTL_WAKEUP_ENA_S);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,371 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stdlib.h>
#include "soc/rtc_io_periph.h"
#include "hal/rtc_io_types.h"
#include "hal/gpio_types.h"
#define RTCIO_LL_PIN_FUNC 0
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
RTCIO_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */
RTCIO_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */
} rtcio_ll_func_t;
typedef enum {
RTCIO_WAKEUP_DISABLE = 0, /*!< Disable GPIO interrupt */
RTCIO_WAKEUP_LOW_LEVEL = 0x4, /*!< GPIO interrupt type : input low level trigger */
RTCIO_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */
} rtcio_ll_wake_type_t;
typedef enum {
RTCIO_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */
RTCIO_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */
} rtcio_ll_out_mode_t;
/**
* @brief Select the rtcio function.
*
* @note The RTC function must be selected before the pad analog function is enabled.
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
* @param func Select pin function.
*/
static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func)
{
if (func == RTCIO_FUNC_RTC) {
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
// 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module.
SET_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
//0:RTC FUNCTION 1,2,3:Reserved
SET_PERI_REG_BITS(rtc_io_desc[rtcio_num].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, RTCIO_LL_PIN_FUNC, rtc_io_desc[rtcio_num].func);
} else if (func == RTCIO_FUNC_DIGITAL) {
CLEAR_PERI_REG_MASK(rtc_io_desc[rtcio_num].reg, (rtc_io_desc[rtcio_num].mux));
SENS.sar_io_mux_conf.iomux_clk_gate_en = 0;
}
}
/**
* 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)
{
SET_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_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)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_PAD_HOLD_REG, rtc_io_desc[rtcio_num].hold_force);
}
/**
* 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_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PAD_FORCE_HOLD_M);
}
/**
* 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)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_PWC_REG, RTC_CNTL_PAD_FORCE_HOLD_M);
}
/**
* 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)
{
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
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)
{
SENS.sar_io_mux_conf.iomux_clk_gate_en = 0;
RTCIO.pin[rtcio_num].wakeup_enable = 0;
RTCIO.pin[rtcio_num].int_type = RTCIO_WAKEUP_DISABLE;
}
/**
* Enable rtc io output in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_enable_output_in_sleep(gpio_num_t gpio_num)
{
if (rtc_io_desc[gpio_num].slpoe) {
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
}
}
/**
* Disable rtc io output in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_disable_output(gpio_num_t gpio_num)
{
if (rtc_io_desc[gpio_num].slpoe) {
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpoe);
}
}
/**
* Enable rtc io input in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_enable_input(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
}
/**
* Disable rtc io input in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_in_sleep_disable_input(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpie);
}
/**
* Enable rtc io keep another setting in deep sleep.
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_enable_sleep_setting(gpio_num_t gpio_num)
{
SET_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
}
/**
* Disable rtc io keep another setting in deep sleep. (Default)
*
* @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio).
*/
static inline void rtcio_ll_disable_sleep_setting(gpio_num_t gpio_num)
{
CLEAR_PERI_REG_MASK(rtc_io_desc[gpio_num].reg, rtc_io_desc[gpio_num].slpsel);
}
static inline void rtcio_ll_ext0_set_wakeup_pin(int rtcio_num, int level)
{
REG_SET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL, rtcio_num);
// Set level which will trigger wakeup
SET_PERI_REG_BITS(RTC_CNTL_EXT_WAKEUP_CONF_REG, 0x1,
level , RTC_CNTL_EXT_WAKEUP0_LV_S);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,311 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The LL layer for Timer Group register operations.
// Note that most of the register operations in this layer are non-atomic operations.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdbool.h>
#include "hal/wdt_types.h"
#include "soc/rtc_cntl_periph.h"
#include "soc/efuse_reg.h"
#include "esp_attr.h"
//Type check wdt_stage_action_t
_Static_assert(WDT_STAGE_ACTION_OFF == RTC_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_INT == RTC_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_CPU == RTC_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_SYSTEM == RTC_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
_Static_assert(WDT_STAGE_ACTION_RESET_RTC == RTC_WDT_STG_SEL_RESET_RTC, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_stage_action_t");
//Type check wdt_reset_sig_length_t
_Static_assert(WDT_RESET_SIG_LENGTH_100ns == RTC_WDT_RESET_LENGTH_100_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_200ns == RTC_WDT_RESET_LENGTH_200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_300ns == RTC_WDT_RESET_LENGTH_300_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_400ns == RTC_WDT_RESET_LENGTH_400_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_500ns == RTC_WDT_RESET_LENGTH_500_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_800ns == RTC_WDT_RESET_LENGTH_800_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_1_6us == RTC_WDT_RESET_LENGTH_1600_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
_Static_assert(WDT_RESET_SIG_LENGTH_3_2us == RTC_WDT_RESET_LENGTH_3200_NS, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with wdt_reset_sig_length_t");
/**
* @brief Enable the RWDT
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_enable(rtc_cntl_dev_t *hw)
{
hw->wdt_config0.en = 1;
}
/**
* @brief Disable the RWDT
*
* @param hw Start address of the peripheral registers.
* @note This function does not disable the flashboot mode. Therefore, given that
* the MWDT is disabled using this function, a timeout can still occur
* if the flashboot mode is simultaneously enabled.
*/
FORCE_INLINE_ATTR void rwdt_ll_disable(rtc_cntl_dev_t *hw)
{
hw->wdt_config0.en = 0;
}
/**
* @brief Check if the RWDT is enabled
*
* @param hw Start address of the peripheral registers.
* @return True if RTC WDT is enabled
*/
FORCE_INLINE_ATTR bool rwdt_ll_check_if_enabled(rtc_cntl_dev_t *hw)
{
return (hw->wdt_config0.en) ? true : false;
}
/**
* @brief Configure a particular stage of the RWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to configure
* @param timeout Number of timer ticks for the stage to timeout (see note).
* @param behavior What action to take when the stage times out
*
* @note The value of of RWDT stage 0 timeout register is special, in
* that an implicit multiplier is applied to that value to produce
* and effective timeout tick value. The multiplier is dependent
* on an EFuse value. Therefore, when configuring stage 0, the valid
* values for the timeout argument are:
* - If Efuse value is 0, any even number between [2,2*UINT32_MAX]
* - If Efuse value is 1, any multiple of 4 between [4,4*UINT32_MAX]
* - If Efuse value is 2, any multiple of 8 between [8,8*UINT32_MAX]
* - If Efuse value is 3, any multiple of 16 between [16,16*UINT32_MAX]
*/
FORCE_INLINE_ATTR void rwdt_ll_config_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = behavior;
//Account of implicty multiplier applied to stage 0 timeout tick config value
hw->wdt_config1 = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL));
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = behavior;
hw->wdt_config2 = timeout_ticks;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = behavior;
hw->wdt_config3 = timeout_ticks;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = behavior;
hw->wdt_config4 = timeout_ticks;
break;
default:
abort();
}
}
/**
* @brief Disable a particular stage of the RWDT
*
* @param hw Start address of the peripheral registers.
* @param stage Which stage to disable
*/
FORCE_INLINE_ATTR void rwdt_ll_disable_stage(rtc_cntl_dev_t *hw, wdt_stage_t stage)
{
switch (stage) {
case WDT_STAGE0:
hw->wdt_config0.stg0 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE1:
hw->wdt_config0.stg1 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE2:
hw->wdt_config0.stg2 = WDT_STAGE_ACTION_OFF;
break;
case WDT_STAGE3:
hw->wdt_config0.stg3 = WDT_STAGE_ACTION_OFF;
break;
default:
abort();
}
}
/**
* @brief Set the length of the CPU reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of CPU reset signal
*/
FORCE_INLINE_ATTR void rwdt_ll_set_cpu_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.cpu_reset_length = length;
}
/**
* @brief Set the length of the system reset action
*
* @param hw Start address of the peripheral registers.
* @param length Length of system reset signal
*/
FORCE_INLINE_ATTR void rwdt_ll_set_sys_reset_length(rtc_cntl_dev_t *hw, wdt_reset_sig_length_t length)
{
hw->wdt_config0.sys_reset_length = length;
}
/**
* @brief Enable/Disable the RWDT flashboot mode.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable RWDT flashboot mode, false to disable RWDT flashboot mode.
*
* @note Flashboot mode is independent and can trigger a WDT timeout event if the
* WDT's enable bit is set to 0. Flashboot mode for RWDT is automatically enabled
* on flashboot, and should be disabled by software when flashbooting completes.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_flashboot_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.flashboot_mod_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the CPU0 to be reset on WDT_STAGE_ACTION_RESET_CPU
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable CPU0 to be reset, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_procpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.procpu_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the CPU1 to be reset on WDT_STAGE_ACTION_RESET_CPU
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable CPU1 to be reset, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_appcpu_reset_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.appcpu_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable the RWDT pause during sleep functionality
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_pause_in_sleep_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.pause_in_slp = (enable) ? 1 : 0;
}
/**
* @brief Enable/Disable chip reset on RWDT timeout.
*
* A chip reset also resets the analog portion of the chip. It will appear as a
* POWERON reset rather than an RTC reset.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_en(rtc_cntl_dev_t* hw, bool enable)
{
hw->wdt_config0.chip_reset_en = (enable) ? 1 : 0;
}
/**
* @brief Set width of chip reset signal
*
* @param hw Start address of the peripheral registers.
* @param width Width of chip reset signal in terms of number of RTC_SLOW_CLK cycles
*/
FORCE_INLINE_ATTR void rwdt_ll_set_chip_reset_width(rtc_cntl_dev_t *hw, uint32_t width)
{
hw->wdt_config0.chip_reset_width = width;
}
/**
* @brief Feed the RWDT
*
* Resets the current timer count and current stage.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_feed(rtc_cntl_dev_t *hw)
{
hw->wdt_feed.feed = 1;
}
/**
* @brief Enable write protection of the RWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_write_protect_enable(rtc_cntl_dev_t *hw)
{
hw->wdt_wprotect = 0;
}
/**
* @brief Disable write protection of the RWDT registers
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_write_protect_disable(rtc_cntl_dev_t *hw)
{
hw->wdt_wprotect = RTC_CNTL_WDT_WKEY_VALUE;
}
/**
* @brief Enable the RWDT interrupt.
*
* @param hw Start address of the peripheral registers.
* @param enable True to enable RWDT interrupt, false to disable.
*/
FORCE_INLINE_ATTR void rwdt_ll_set_intr_enable(rtc_cntl_dev_t* hw, bool enable)
{
hw->int_ena.rtc_wdt = (enable) ? 1 : 0;
}
/**
* @brief Check if the RWDT interrupt has been triggered
*
* @param hw Start address of the peripheral registers.
* @return True if the RWDT interrupt was triggered
*/
FORCE_INLINE_ATTR bool rwdt_ll_check_intr_status(rtc_cntl_dev_t *hw)
{
return (hw->int_st.rtc_wdt) ? true : false;
}
/**
* @brief Clear the RWDT interrupt status.
*
* @param hw Start address of the peripheral registers.
*/
FORCE_INLINE_ATTR void rwdt_ll_clear_intr_status(rtc_cntl_dev_t* hw)
{
hw->int_clr.rtc_wdt = 1;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,173 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include "soc/hwcrypto_reg.h"
#include "hal/sha_types.h"
#include "soc/dport_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Start a new SHA block conversions (no initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_start_block(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_START_REG, 1);
}
/**
* @brief Continue a SHA block conversion (initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_continue_block(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_CONTINUE_REG, 1);
}
/**
* @brief Start a new SHA message conversion using DMA (no initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_start_dma(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_DMA_START_REG, 1);
}
/**
* @brief Continue a SHA message conversion using DMA (initial hash in HW)
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_continue_dma(esp_sha_type sha_type)
{
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_DMA_CONTINUE_REG, 1);
}
/**
* @brief Load the current hash digest to digest register
*
* @note Happens automatically on ESP32S2
*
* @param sha_type The SHA algorithm type
*/
static inline void sha_ll_load(esp_sha_type sha_type)
{
}
/**
* @brief Sets the number of message blocks to be hashed
*
* @note DMA operation only
*
* @param num_blocks Number of message blocks to process
*/
static inline void sha_ll_set_block_num(size_t num_blocks)
{
REG_WRITE(SHA_BLOCK_NUM_REG, num_blocks);
}
/**
* @brief Checks if the SHA engine is currently busy hashing a block
*
* @return true SHA engine busy
* @return false SHA engine idle
*/
static inline bool sha_ll_busy(void)
{
return REG_READ(SHA_BUSY_REG);
}
/**
* @brief Write a text (message) block to the SHA engine
*
* @param input_text Input buffer to be written to the SHA engine
* @param block_word_len Number of words in block
*/
static inline void sha_ll_fill_text_block(const void *input_text, size_t block_word_len)
{
uint32_t *data_words = (uint32_t *)input_text;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
for (size_t i = 0; i < block_word_len; i++) {
REG_WRITE(&reg_addr_buf[i], data_words[i]);
}
}
/**
* @brief Read the message digest from the SHA engine
*
* @param sha_type The SHA algorithm type
* @param digest_state Buffer that message digest will be written to
* @param digest_word_len Length of the message digest
*/
static inline void sha_ll_read_digest(esp_sha_type sha_type, void *digest_state, size_t digest_word_len)
{
uint32_t *digest_state_words = (uint32_t *)digest_state;
esp_dport_access_read_buffer(digest_state_words, SHA_H_BASE, digest_word_len);
}
/**
* @brief Write the message digest to the SHA engine
*
* @param sha_type The SHA algorithm type
* @param digest_state Message digest to be written to SHA engine
* @param digest_word_len Length of the message digest
*/
static inline void sha_ll_write_digest(esp_sha_type sha_type, void *digest_state, size_t digest_word_len)
{
uint32_t *digest_state_words = (uint32_t *)digest_state;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_H_BASE);
for (size_t i = 0; i < digest_word_len; i++) {
REG_WRITE(&reg_addr_buf[i], digest_state_words[i]);
}
}
/**
* @brief Sets SHA512_t T_string parameter
*
* @param t_string T_string parameter
*/
static inline void sha_ll_t_string_set(uint32_t t_string)
{
REG_WRITE(SHA_T_STRING_REG, t_string);
}
/**
* @brief Sets SHA512_t T_string parameter's length
*
* @param t_len T_string parameter length
*/
static inline void sha_ll_t_len_set(uint8_t t_len)
{
REG_WRITE(SHA_T_LENGTH_REG, t_len);
}
#ifdef __cplusplus
}
#endif

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

View File

@@ -0,0 +1,32 @@
// 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_reset_core(int core)
{
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST_M);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,111 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include "gpspi_flash_ll.h"
#include "spimem_flash_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
// For esp32s2, spimem is equivalent to traditional spi peripherals found
// in esp32. Let the spi flash clock reg definitions reflect this.
#define SPI_FLASH_LL_CLKREG_VAL_5MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_10MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_20MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_26MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_40MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ}
#define SPI_FLASH_LL_CLKREG_VAL_80MHZ {.spimem=SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ}
#define spi_flash_ll_get_hw(host_id) (((host_id)<=SPI1_HOST ? (spi_dev_t*) spimem_flash_ll_get_hw(host_id) \
: gpspi_flash_ll_get_hw(host_id)))
#define spi_flash_ll_hw_get_id(dev) ({int dev_id = spimem_flash_ll_hw_get_id(dev); \
if (dev_id < 0) {\
dev_id = gpspi_flash_ll_hw_get_id(dev);\
}\
dev_id; \
})
typedef union {
gpspi_flash_ll_clock_reg_t gpspi;
spimem_flash_ll_clock_reg_t spimem;
} spi_flash_ll_clock_reg_t;
#ifdef GPSPI_BUILD
#define spi_flash_ll_reset(dev) gpspi_flash_ll_reset((spi_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) gpspi_flash_ll_cmd_is_done((spi_dev_t*)dev)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) gpspi_flash_ll_get_buffer_data((spi_dev_t*)dev, buffer, read_len)
#define spi_flash_ll_set_buffer_data(dev, buffer, len) gpspi_flash_ll_set_buffer_data((spi_dev_t*)dev, buffer, len)
#define spi_flash_ll_user_start(dev) gpspi_flash_ll_user_start((spi_dev_t*)dev)
#define spi_flash_ll_host_idle(dev) gpspi_flash_ll_host_idle((spi_dev_t*)dev)
#define spi_flash_ll_read_phase(dev) gpspi_flash_ll_read_phase((spi_dev_t*)dev)
#define spi_flash_ll_set_cs_pin(dev, pin) gpspi_flash_ll_set_cs_pin((spi_dev_t*)dev, pin)
#define spi_flash_ll_set_read_mode(dev, read_mode) gpspi_flash_ll_set_read_mode((spi_dev_t*)dev, read_mode)
#define spi_flash_ll_set_clock(dev, clk) gpspi_flash_ll_set_clock((spi_dev_t*)dev, (gpspi_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) gpspi_flash_ll_set_miso_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) gpspi_flash_ll_set_mosi_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command(dev, cmd, bitlen) gpspi_flash_ll_set_command((spi_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) gpspi_flash_ll_set_addr_bitlen((spi_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) gpspi_flash_ll_get_addr_bitlen((spi_dev_t*)dev)
#define spi_flash_ll_set_address(dev, addr) gpspi_flash_ll_set_address((spi_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) gpspi_flash_ll_set_usr_address((spi_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) gpspi_flash_ll_set_dummy((spi_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) gpspi_flash_ll_set_dummy_out((spi_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) gpspi_flash_ll_set_hold((spi_dev_t*)dev, hold_n)
#else
#define spi_flash_ll_reset(dev) spimem_flash_ll_reset((spi_mem_dev_t*)dev)
#define spi_flash_ll_cmd_is_done(dev) spimem_flash_ll_cmd_is_done((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_chip(dev) spimem_flash_ll_erase_chip((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_sector(dev) spimem_flash_ll_erase_sector((spi_mem_dev_t*)dev)
#define spi_flash_ll_erase_block(dev) spimem_flash_ll_erase_block((spi_mem_dev_t*)dev)
#define spi_flash_ll_set_write_protect(dev, wp) spimem_flash_ll_set_write_protect((spi_mem_dev_t*)dev, wp)
#define spi_flash_ll_get_buffer_data(dev, buffer, read_len) spimem_flash_ll_get_buffer_data((spi_mem_dev_t*)dev, buffer, read_len)
#define spi_flash_ll_set_buffer_data(dev, buffer, len) spimem_flash_ll_set_buffer_data((spi_mem_dev_t*)dev, buffer, len)
#define spi_flash_ll_program_page(dev, buffer, len) spimem_flash_ll_program_page((spi_mem_dev_t*)dev, buffer, len)
#define spi_flash_ll_user_start(dev) spimem_flash_ll_user_start((spi_mem_dev_t*)dev)
#define spi_flash_ll_host_idle(dev) spimem_flash_ll_host_idle((spi_mem_dev_t*)dev)
#define spi_flash_ll_read_phase(dev) spimem_flash_ll_read_phase((spi_mem_dev_t*)dev)
#define spi_flash_ll_set_cs_pin(dev, pin) spimem_flash_ll_set_cs_pin((spi_mem_dev_t*)dev, pin)
#define spi_flash_ll_set_read_mode(dev, read_mode) spimem_flash_ll_set_read_mode((spi_mem_dev_t*)dev, read_mode)
#define spi_flash_ll_set_clock(dev, clk) spimem_flash_ll_set_clock((spi_mem_dev_t*)dev, (spimem_flash_ll_clock_reg_t*)clk)
#define spi_flash_ll_set_miso_bitlen(dev, bitlen) spimem_flash_ll_set_miso_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_mosi_bitlen(dev, bitlen) spimem_flash_ll_set_mosi_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_set_command(dev, cmd, bitlen) spimem_flash_ll_set_command((spi_mem_dev_t*)dev, cmd, bitlen)
#define spi_flash_ll_set_addr_bitlen(dev, bitlen) spimem_flash_ll_set_addr_bitlen((spi_mem_dev_t*)dev, bitlen)
#define spi_flash_ll_get_addr_bitlen(dev) spimem_flash_ll_get_addr_bitlen((spi_mem_dev_t*) dev)
#define spi_flash_ll_set_address(dev, addr) spimem_flash_ll_set_address((spi_mem_dev_t*)dev, addr)
#define spi_flash_ll_set_usr_address(dev, addr, bitlen) spimem_flash_ll_set_usr_address((spi_mem_dev_t*)dev, addr, bitlen)
#define spi_flash_ll_set_dummy(dev, dummy) spimem_flash_ll_set_dummy((spi_mem_dev_t*)dev, dummy)
#define spi_flash_ll_set_dummy_out(dev, en, lev) spimem_flash_ll_set_dummy_out((spi_mem_dev_t*)dev, en, lev)
#define spi_flash_ll_set_hold(dev, hold_n) spimem_flash_ll_set_hold((spi_mem_dev_t*)dev, hold_n)
#endif
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,545 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for SPI Flash
#pragma once
#include <stdlib.h>
#include <sys/param.h> // For MIN/MAX
#include <stdbool.h>
#include <string.h>
#include "soc/spi_periph.h"
#include "hal/spi_types.h"
#include "hal/spi_flash_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define spimem_flash_ll_get_hw(host_id) (((host_id)==SPI1_HOST ? &SPIMEM1 : NULL ))
#define spimem_flash_ll_hw_get_id(dev) ((dev) == (void*)&SPIMEM1? SPI1_HOST: -1)
typedef typeof(SPIMEM1.clock) spimem_flash_ll_clock_reg_t;
//Supported clock register values
#define SPIMEM_FLASH_LL_CLKREG_VAL_5MHZ ((spimem_flash_ll_clock_reg_t){.val=0x000F070F}) ///< Clock set to 5 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_10MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00070307}) ///< Clock set to 10 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_20MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00030103}) ///< Clock set to 20 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_26MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00020002}) ///< Clock set to 26 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_40MHZ ((spimem_flash_ll_clock_reg_t){.val=0x00010001}) ///< Clock set to 40 MHz
#define SPIMEM_FLASH_LL_CLKREG_VAL_80MHZ ((spimem_flash_ll_clock_reg_t){.val=0x80000000}) ///< Clock set to 80 MHz
/*------------------------------------------------------------------------------
* Control
*----------------------------------------------------------------------------*/
/**
* Reset peripheral registers before configuration and starting control
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_reset(spi_mem_dev_t *dev)
{
dev->user.val = 0;
dev->ctrl.val = 0;
}
/**
* Check whether the previous operation is done.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if last command is done, otherwise false.
*/
static inline bool spimem_flash_ll_cmd_is_done(const spi_mem_dev_t *dev)
{
return (dev->cmd.val == 0);
}
/**
* Erase the flash chip.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_chip(spi_mem_dev_t *dev)
{
dev->cmd.flash_ce = 1;
}
/**
* Erase the sector, the address should be set by spimem_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_sector(spi_mem_dev_t *dev)
{
dev->ctrl.val = 0;
dev->cmd.flash_se = 1;
}
/**
* Erase the block, the address should be set by spimem_flash_ll_set_address.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_erase_block(spi_mem_dev_t *dev)
{
dev->cmd.flash_be = 1;
}
/**
* Suspend erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_suspend(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_pes = 1;
}
/**
* Resume suspended erase/program operation.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_resume(spi_mem_dev_t *dev)
{
dev->flash_sus_cmd.flash_per = 1;
}
/**
* Initialize auto suspend mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_sus Enable/disable Flash Auto-Suspend.
*/
static inline void spimem_flash_ll_auto_suspend_init(spi_mem_dev_t *dev, bool auto_sus)
{
dev->flash_sus_ctrl.flash_pes_en = auto_sus;
}
/**
* Initialize auto resume mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_res Enable/Disable Flash Auto-Resume.
*
*/
static inline void spimem_flash_ll_auto_resume_init(spi_mem_dev_t *dev, bool auto_res)
{
dev->misc.auto_per = 0; // Must disable Hardware Auto-Resume (should not be enabled, ESP32-S2 has bugs).
}
/**
* Set 8 bit command to read suspend status
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_set_read_sus_status(spi_mem_dev_t *dev, uint32_t sus_mask)
{
abort();// Not supported on esp32s2
}
/**
* Setup the flash suspend command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_cmd Flash suspend command.
*
*/
static inline void spimem_flash_ll_suspend_cmd_setup(spi_mem_dev_t *dev, uint32_t sus_cmd)
{
dev->flash_sus_ctrl.flash_pes_command = sus_cmd;
}
/**
* Setup the flash resume command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param res_cmd Flash resume command.
*
*/
static inline void spimem_flash_ll_resume_cmd_setup(spi_mem_dev_t *dev, uint32_t res_cmd)
{
dev->flash_sus_ctrl.flash_per_command = res_cmd;
}
/**
* Setup the flash read suspend status command, may vary from chips to chips.
*
* @param dev Beginning address of the peripheral registers.
* @param pesr_cmd Flash read suspend status command.
*
*/
static inline void spimem_flash_ll_rd_sus_cmd_setup(spi_mem_dev_t *dev, uint32_t pesr_cmd)
{
abort();// Not supported on esp32s2
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the suspend status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_sus_check_sus_setup(spi_mem_dev_t *dev, bool sus_check_sus_en)
{
abort();// Not supported on esp32s2
}
/**
* Setup to check SUS/SUS1/SUS2 to ensure the resume status of flashs.
*
* @param dev Beginning address of the peripheral registers.
* @param sus_check_sus_en 1: enable, 0: disable.
*
*/
static inline void spimem_flash_ll_res_check_sus_setup(spi_mem_dev_t *dev, bool res_check_sus_en)
{
abort();// Not supported on esp32s2
}
/**
* Initialize auto wait idle mode
*
* @param dev Beginning address of the peripheral registers.
* @param auto_waiti Enable/disable auto wait-idle function
*/
static inline void spimem_flash_ll_auto_wait_idle_init(spi_mem_dev_t *dev, bool auto_waiti)
{
dev->flash_waiti_ctrl.waiti_cmd = 0x05; // Set the command to send, to fetch flash status reg value.
dev->flash_waiti_ctrl.waiti_en = auto_waiti; // enable auto wait-idle function.
}
/**
* Return the suspend status of erase or program operations.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if suspended, otherwise false.
*/
static inline bool spimem_flash_ll_sus_status(spi_mem_dev_t *dev)
{
return dev->sus_status.flash_sus;
}
/**
* Enable/disable write protection for the flash chip.
*
* @param dev Beginning address of the peripheral registers.
* @param wp true to enable the protection, false to disable (write enable).
*/
static inline void spimem_flash_ll_set_write_protect(spi_mem_dev_t *dev, bool wp)
{
if (wp) {
dev->cmd.flash_wrdi = 1;
} else {
dev->cmd.flash_wren = 1;
}
}
/**
* Get the read data from the buffer after ``spimem_flash_ll_read`` is done.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer to hold the output data
* @param read_len Length to get out of the buffer
*/
static inline void spimem_flash_ll_get_buffer_data(spi_mem_dev_t *dev, void *buffer, uint32_t read_len)
{
if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) {
// If everything is word-aligned, do a faster memcpy
memcpy(buffer, (void *)dev->data_buf, read_len);
} else {
// Otherwise, slow(er) path copies word by word
int copy_len = read_len;
for (size_t i = 0; i < (read_len + 3) / 4; i++) {
int word_len = MIN(sizeof(uint32_t), copy_len);
uint32_t word = dev->data_buf[i];
memcpy(buffer, &word, word_len);
buffer = (void *)((intptr_t)buffer + word_len);
copy_len -= word_len;
}
}
}
/**
* Set the data to be written in the data buffer.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer holding the data
* @param length Length of data in bytes.
*/
static inline void spimem_flash_ll_set_buffer_data(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
{
// Load data registers, word at a time
int num_words = (length + 3) / 4;
for (int i = 0; i < num_words; i++) {
uint32_t word = 0;
uint32_t word_len = MIN(length, sizeof(word));
memcpy(&word, buffer, word_len);
dev->data_buf[i] = word;
length -= word_len;
buffer = (void *)((intptr_t)buffer + word_len);
}
}
/**
* Program a page of the flash chip. Call ``spimem_flash_ll_set_address`` before
* this to set the address to program.
*
* @param dev Beginning address of the peripheral registers.
* @param buffer Buffer holding the data to program
* @param length Length to program.
*/
static inline void spimem_flash_ll_program_page(spi_mem_dev_t *dev, const void *buffer, uint32_t length)
{
dev->user.usr_dummy = 0;
spimem_flash_ll_set_buffer_data(dev, buffer, length);
dev->cmd.flash_pp = 1;
}
/**
* Trigger a user defined transaction. All phases, including command, address, dummy, and the data phases,
* should be configured before this is called.
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_user_start(spi_mem_dev_t *dev)
{
dev->cmd.usr = 1;
}
/**
* Check whether the host is idle to perform new commands.
*
* @param dev Beginning address of the peripheral registers.
*
* @return true if the host is idle, otherwise false
*/
static inline bool spimem_flash_ll_host_idle(const spi_mem_dev_t *dev)
{
return dev->fsm.st == 0;
}
/**
* Set phases for user-defined transaction to read
*
* @param dev Beginning address of the peripheral registers.
*/
static inline void spimem_flash_ll_read_phase(spi_mem_dev_t *dev)
{
typeof (dev->user) user = {
.usr_command = 1,
.usr_mosi = 0,
.usr_miso = 1,
.usr_addr = 1,
};
dev->user = user;
}
/*------------------------------------------------------------------------------
* Configs
*----------------------------------------------------------------------------*/
/**
* Select which pin to use for the flash
*
* @param dev Beginning address of the peripheral registers.
* @param pin Pin ID to use, 0-1. Set to other values to disable all the CS pins.
*/
static inline void spimem_flash_ll_set_cs_pin(spi_mem_dev_t *dev, int pin)
{
dev->misc.cs0_dis = (pin != 0);
dev->misc.cs1_dis = (pin != 1);
}
/**
* Set the read io mode.
*
* @param dev Beginning address of the peripheral registers.
* @param read_mode I/O mode to use in the following transactions.
*/
static inline void spimem_flash_ll_set_read_mode(spi_mem_dev_t *dev, esp_flash_io_mode_t read_mode)
{
typeof (dev->ctrl) ctrl = dev->ctrl;
ctrl.val &= ~(SPI_MEM_FREAD_QIO_M | SPI_MEM_FREAD_QUAD_M | SPI_MEM_FREAD_DIO_M | SPI_MEM_FREAD_DUAL_M);
ctrl.val |= SPI_MEM_FASTRD_MODE_M;
switch (read_mode) {
case SPI_FLASH_FASTRD:
//the default option
break;
case SPI_FLASH_QIO:
ctrl.fread_qio = 1;
break;
case SPI_FLASH_QOUT:
ctrl.fread_quad = 1;
break;
case SPI_FLASH_DIO:
ctrl.fread_dio = 1;
break;
case SPI_FLASH_DOUT:
ctrl.fread_dual = 1;
break;
case SPI_FLASH_SLOWRD:
ctrl.fastrd_mode = 0;
break;
default:
abort();
}
dev->ctrl = ctrl;
}
/**
* Set clock frequency to work at.
*
* @param dev Beginning address of the peripheral registers.
* @param clock_val pointer to the clock value to set
*/
static inline void spimem_flash_ll_set_clock(spi_mem_dev_t *dev, spimem_flash_ll_clock_reg_t *clock_val)
{
dev->clock = *clock_val;
}
/**
* Set the input length, in bits.
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of input, in bits.
*/
static inline void spimem_flash_ll_set_miso_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_miso = bitlen > 0;
dev->miso_dlen.usr_miso_bit_len = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the output length, in bits (not including command, address and dummy
* phases)
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of output, in bits.
*/
static inline void spimem_flash_ll_set_mosi_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
{
dev->user.usr_mosi = bitlen > 0;
dev->mosi_dlen.usr_mosi_bit_len = bitlen ? (bitlen - 1) : 0;
}
/**
* Set the command.
*
* @param dev Beginning address of the peripheral registers.
* @param command Command to send
* @param bitlen Length of the command
*/
static inline void spimem_flash_ll_set_command(spi_mem_dev_t *dev, uint32_t command, uint32_t bitlen)
{
dev->user.usr_command = 1;
typeof(dev->user2) user2 = {
.usr_command_value = command,
.usr_command_bitlen = (bitlen - 1),
};
dev->user2 = user2;
}
/**
* Get the address length that is set in register, in bits.
*
* @param dev Beginning address of the peripheral registers.
*
*/
static inline int spimem_flash_ll_get_addr_bitlen(spi_mem_dev_t *dev)
{
return dev->user.usr_addr ? dev->user1.usr_addr_bitlen + 1 : 0;
}
/**
* Set the address length to send, in bits. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param bitlen Length of the address, in bits
*/
static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t bitlen)
{
dev->user1.usr_addr_bitlen = (bitlen - 1);
dev->user.usr_addr = bitlen ? 1 : 0;
}
/**
* Set the address to send. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_address(spi_mem_dev_t *dev, uint32_t addr)
{
dev->addr = addr;
}
/**
* Set the address to send in user mode. Should be called before commands that requires the address e.g. erase sector, read, write...
*
* @param dev Beginning address of the peripheral registers.
* @param addr Address to send
*/
static inline void spimem_flash_ll_set_usr_address(spi_mem_dev_t *dev, uint32_t addr, uint32_t bitlen)
{
(void)bitlen;
spimem_flash_ll_set_address(dev, addr);
}
/**
* Set the length of dummy cycles.
*
* @param dev Beginning address of the peripheral registers.
* @param dummy_n Cycles of dummy phases
*/
static inline void spimem_flash_ll_set_dummy(spi_mem_dev_t *dev, uint32_t dummy_n)
{
dev->user.usr_dummy = dummy_n ? 1 : 0;
dev->user1.usr_dummy_cyclelen = dummy_n - 1;
}
/**
* Set D/Q output level during dummy phase
*
* @param dev Beginning address of the peripheral registers.
* @param out_en whether to enable IO output for dummy phase
* @param out_level dummy output level
*/
static inline void spimem_flash_ll_set_dummy_out(spi_mem_dev_t *dev, uint32_t out_en, uint32_t out_lev)
{
dev->ctrl.fdummy_out = out_en;
dev->ctrl.q_pol = out_lev;
dev->ctrl.d_pol = out_lev;
}
static inline void spimem_flash_ll_set_hold(spi_mem_dev_t *dev, uint32_t hold_n)
{
dev->ctrl2.cs_hold_time = hold_n - 1;
dev->user.cs_hold = (hold_n > 0? 1: 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,138 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc.h"
#include "soc/systimer_reg.h"
// All these functions get invoked either from ISR or HAL that linked to IRAM.
// Always inline these functions even no gcc optimization is applied.
/*******************counter*************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_clock(void)
{
REG_SET_BIT(SYSTIMER_CONF_REG, SYSTIMER_CLK_EN);
}
__attribute__((always_inline)) static inline void systimer_ll_apply_counter_value(void)
{
REG_SET_BIT(SYSTIMER_LOAD_REG, SYSTIMER_TIMER_LOAD);
}
__attribute__((always_inline)) static inline void systimer_ll_load_counter_value(uint64_t value)
{
REG_WRITE(SYSTIMER_LOAD_LO_REG, value & 0xFFFFFFFF);
REG_WRITE(SYSTIMER_LOAD_HI_REG, (value & 0xFFFFFFFF00000000) >> 32);
}
__attribute__((always_inline)) static inline void systimer_ll_set_step_for_pll(uint32_t step)
{
REG_SET_FIELD(SYSTIMER_STEP_REG, SYSTIMER_TIMER_PLL_STEP, step);
}
__attribute__((always_inline)) static inline void systimer_ll_set_step_for_xtal(uint32_t step)
{
REG_SET_FIELD(SYSTIMER_STEP_REG, SYSTIMER_TIMER_XTAL_STEP, step);
}
__attribute__((always_inline)) static inline void systimer_ll_counter_snapshot(void)
{
REG_WRITE(SYSTIMER_UPDATE_REG, SYSTIMER_TIMER_UPDATE);
}
__attribute__((always_inline)) static inline bool systimer_ll_is_counter_value_valid(void)
{
return REG_GET_BIT(SYSTIMER_UPDATE_REG, SYSTIMER_TIMER_VALUE_VALID);
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_low(void)
{
return REG_READ(SYSTIMER_VALUE_LO_REG);
}
__attribute__((always_inline)) static inline uint32_t systimer_ll_get_counter_value_high(void)
{
return REG_READ(SYSTIMER_VALUE_HI_REG);
}
/*******************alarm*************************/
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_value(uint32_t alarm_id, uint64_t value)
{
REG_WRITE(SYSTIMER_TARGET0_LO_REG + alarm_id * 8, value & 0xFFFFFFFF);
REG_WRITE(SYSTIMER_TARGET0_HI_REG + alarm_id * 8, (value & 0xFFFFFFFF00000000) >> 32);
}
__attribute__((always_inline)) static inline uint64_t systimer_ll_get_alarm_value(uint32_t alarm_id)
{
return (uint64_t)REG_READ(SYSTIMER_TARGET0_HI_REG + alarm_id * 8) << 32 | REG_READ(SYSTIMER_TARGET0_LO_REG + alarm_id * 8);
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm(uint32_t alarm_id)
{
REG_SET_BIT(SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, BIT(31));
}
__attribute__((always_inline)) static inline void systimer_ll_disable_alarm(uint32_t alarm_id)
{
REG_CLR_BIT(SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, BIT(31));
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_oneshot(uint32_t alarm_id)
{
REG_CLR_BIT(SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, BIT(30));
}
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_period(uint32_t alarm_id)
{
REG_SET_BIT(SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, BIT(30));
}
__attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(uint32_t alarm_id, uint32_t period)
{
REG_SET_FIELD(SYSTIMER_TARGET0_CONF_REG + alarm_id * 4, SYSTIMER_TARGET0_PERIOD, period);
}
/*******************interrupt*************************/
__attribute__((always_inline)) static inline void systimer_ll_enable_alarm_int(uint32_t alarm_id)
{
REG_SET_BIT(SYSTIMER_INT_ENA_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_disable_alarm_int(uint32_t alarm_id)
{
REG_CLR_BIT(SYSTIMER_INT_ENA_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline bool systimer_ll_is_alarm_int_fired(uint32_t alarm_id)
{
return REG_GET_BIT(SYSTIMER_INT_RAW_REG, 1 << alarm_id);
}
__attribute__((always_inline)) static inline void systimer_ll_clear_alarm_int(uint32_t alarm_id)
{
REG_SET_BIT(SYSTIMER_INT_CLR_REG, 1 << alarm_id);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,425 @@
// 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 is not valid)
*
* @return None
*/
static inline void timer_ll_set_divider(timg_dev_t *hw, timer_idx_t timer_num, uint32_t divider)
{
assert(divider >= 2 && divider <= 65536);
if (divider >= 65536) {
divider = 0;
}
int timer_en = hw->hw_timer[timer_num].config.enable;
hw->hw_timer[timer_num].config.enable = 0;
hw->hw_timer[timer_num].config.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.update = 1;
while (hw->hw_timer[timer_num].update.update) {}
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
}
/**
* @brief Set counter mode, include increment mode and decrement mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param increase_en True to increment mode, fasle to decrement mode
*
* @return None
*/
static inline void timer_ll_set_counter_increase(timg_dev_t *hw, timer_idx_t timer_num, bool increase_en)
{
hw->hw_timer[timer_num].config.increase = increase_en;
}
/**
* @brief Get counter mode, include increment mode and decrement mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Increment mode
* - false Decrement mode
*/
static inline bool timer_ll_get_counter_increase(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.increase;
}
/**
* @brief Set counter status, enable or disable counter.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param counter_en True to enable counter, false to disable counter
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, bool counter_en)
{
hw->hw_timer[timer_num].config.enable = counter_en;
}
/**
* @brief Get counter status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable counter
* - false Disable conuter
*/
static inline bool timer_ll_get_counter_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.enable;
}
/**
* @brief Set auto reload mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
*
* @return None
*/
static inline void timer_ll_set_auto_reload(timg_dev_t *hw, timer_idx_t timer_num, bool auto_reload_en)
{
hw->hw_timer[timer_num].config.autoreload = auto_reload_en;
}
/**
* @brief Get auto reload mode.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable auto reload mode
* - false Disable auto reload mode
*/
FORCE_INLINE_ATTR bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.autoreload;
}
/**
* @brief Set the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Counter value to trigger the alarm
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
{
hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
}
/**
* @brief Get the counter value to trigger the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_value Pointer to accept the counter value to trigger the alarm
*
* @return None
*/
static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value)
{
*alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low);
}
/**
* @brief Set the alarm status, enable or disable the alarm.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param alarm_en True to enable alarm, false to disable alarm
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
{
hw->hw_timer[timer_num].config.alarm_en = alarm_en;
}
/**
* @brief Get the alarm status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable alarm
* - false Disable alarm
*/
static inline bool timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.alarm_en;
}
/**
* @brief Enable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_intr_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_ena.val |= BIT(timer_num);
hw->hw_timer[timer_num].config.level_int_en = 1;
}
/**
* @brief Disable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_intr_disable(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_ena.val &= (~BIT(timer_num));
hw->hw_timer[timer_num].config.level_int_en = 0;
}
/**
* @brief Disable timer interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_clear_intr_status(timg_dev_t *hw, timer_idx_t timer_num)
{
hw->int_clr.val |= BIT(timer_num);
}
/**
* @brief Get interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param intr_status Interrupt status
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_get_intr_status(timg_dev_t *hw, uint32_t *intr_status)
{
*intr_status = hw->int_st.val & 0x03;
}
/**
* @brief Get interrupt raw status.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_raw_status Interrupt raw status
*
* @return None
*/
FORCE_INLINE_ATTR void timer_ll_get_intr_raw_status(timer_group_t group_num, uint32_t *intr_raw_status)
{
timg_dev_t *hw = TIMER_LL_GET_HW(group_num);
*intr_raw_status = hw->int_raw.val & 0x03;
}
/**
* @brief Set the level interrupt status, enable or disable the level interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param level_int_en True to enable level interrupt, false to disable level interrupt
*
* @return None
*/
static inline void timer_ll_set_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool level_int_en)
{
hw->hw_timer[timer_num].config.level_int_en = level_int_en;
}
/**
* @brief Get the level interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable level interrupt
* - false Disable level interrupt
*/
static inline bool timer_ll_get_level_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.level_int_en;
}
/**
* @brief Set the edge interrupt status, enable or disable the edge interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
* @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
*
* @return None
*/
static inline void timer_ll_set_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num, bool edge_int_en)
{
hw->hw_timer[timer_num].config.edge_int_en = edge_int_en;
}
/**
* @brief Get the edge interrupt status.
*
* @param hw Beginning address of the peripheral registers.
* @param timer_num The timer number
*
* @return
* - true Enable edge interrupt
* - false Disable edge interrupt
*/
static inline bool timer_ll_get_edge_int_enable(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.edge_int_en;
}
/**
* @brief Get interrupt status register address.
*
* @param hw Beginning address of the peripheral registers.
*
* @return uint32_t Interrupt status register address
*/
static inline uint32_t timer_ll_get_intr_status_reg(timg_dev_t *hw)
{
return (uint32_t) & (hw->int_st.val);
}
static inline uint32_t timer_ll_get_intr_mask_bit(timg_dev_t *hw, timer_idx_t timer_num)
{
return (1U << timer_num);
}
/**
* @brief Set clock source.
*
* @param hal Context of the HAL layer
* @param use_xtal_en True to use XTAL clock, flase to use APB clock
*
* @return None
*/
static inline void timer_ll_set_use_xtal(timg_dev_t *hw, timer_idx_t timer_num, bool use_xtal_en)
{
hw->hw_timer[timer_num].config.use_xtal = use_xtal_en;
}
/**
* @brief Get clock source.
*
* @param hal Context of the HAL layer
*
* @return
* - true Use XTAL clock
* - false Use APB clock
*/
static inline bool timer_ll_get_use_xtal(timg_dev_t *hw, timer_idx_t timer_num)
{
return hw->hw_timer[timer_num].config.use_xtal;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,640 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for touch sensor (ESP32-S2 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
/**
* Reset the whole of touch module.
*
* @note Call this funtion after `touch_pad_fsm_stop`,
*/
#define touch_hal_reset() touch_ll_reset()
/**
* 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_times(meas_time) touch_ll_set_meas_times(meas_time)
/**
* Get touch sensor times of charge and discharge.
*
* @param meas_times Pointer to accept times count of charge and discharge.
*/
#define touch_hal_get_measure_times(meas_time) touch_ll_get_measure_times(meas_time)
/**
* Set connection type of touch channel in idle status.
* When a channel is in measurement mode, other initialized channels are in idle mode.
* The touch channel is generally adjacent to the trace, so the connection state of the idle channel
* affects the stability and sensitivity of the test channel.
* The `CONN_HIGHZ`(high resistance) setting increases the sensitivity of touch channels.
* The `CONN_GND`(grounding) setting increases the stability of touch channels.
*
* @param type Select idle channel connect to high resistance state or ground.
*/
#define touch_hal_set_idle_channel_connect(type) touch_ll_set_idle_channel_connect(type)
/**
* Set connection type of touch channel in idle status.
* When a channel is in measurement mode, other initialized channels are in idle mode.
* The touch channel is generally adjacent to the trace, so the connection state of the idle channel
* affects the stability and sensitivity of the test channel.
* The `CONN_HIGHZ`(high resistance) setting increases the sensitivity of touch channels.
* The `CONN_GND`(grounding) setting increases the stability of touch channels.
*
* @param type Select idle channel connect to high resistance state or ground.
*/
#define touch_hal_get_idle_channel_connect(type) touch_ll_get_idle_channel_connect(type)
/**
* Get the current measure channel. Touch sensor measurement is cyclic scan mode.
*
* @return
* - touch channel number
*/
#define touch_hal_get_current_meas_channel() touch_ll_get_current_meas_channel()
/**
* Enable touch sensor interrupt by bitmask.
*
* @param type interrupt type
*/
#define touch_hal_intr_enable(int_mask) touch_ll_intr_enable(int_mask)
/**
* Disable touch sensor interrupt by bitmask.
*
* @param type interrupt type
*/
#define touch_hal_intr_disable(int_mask) touch_ll_intr_disable(int_mask)
/**
* Clear touch sensor interrupt by bitmask.
*
* @param int_mask Pad mask to clear interrupts
*/
#define touch_hal_intr_clear(int_mask) touch_ll_intr_clear(int_mask)
/**
* Get the bitmask of touch sensor interrupt status.
*
* @return type interrupt type
*/
#define touch_hal_read_intr_status_mask() touch_ll_read_intr_status_mask()
/**
* Enable the timeout check for all touch sensor channels measurements.
* When the touch reading of a touch channel exceeds the measurement threshold,
* If enable: a timeout interrupt will be generated and it will go to the next channel measurement.
* If disable: the FSM is always on the channel, until the measurement of this channel is over.
*
* @note Set the timeout threshold correctly before enabling it.
*/
#define touch_hal_timeout_enable() touch_ll_timeout_enable()
/**
* Disable the timeout check for all touch sensor channels measurements.
* When the touch reading of a touch channel exceeds the measurement threshold,
* If enable: a timeout interrupt will be generated and it will go to the next channel measurement.
* If disable: the FSM is always on the channel, until the measurement of this channel is over.
*
* @note Set the timeout threshold correctly before enabling it.
*/
#define touch_hal_timeout_disable() touch_ll_timeout_disable()
/**
* Set timeout threshold for all touch sensor channels measurements.
* Compared with touch readings.
*
* @param threshold Set to the maximum time measured on one channel.
*/
#define touch_hal_timeout_set_threshold(threshold) touch_ll_timeout_set_threshold(threshold)
/**
* Get timeout threshold for all touch sensor channels measurements.
* Compared with touch readings.
*
* @param threshold Point to timeout threshold.
*/
#define touch_hal_timeout_get_threshold(threshold) touch_ll_timeout_get_threshold(threshold)
/**
* Touch timer trigger measurement and always wait measurement done.
* Force done for touch timer ensures that the timer always can get the measurement done signal.
*/
#define touch_hal_timer_force_done() touch_ll_timer_force_done()
/************************ Filter register setting ************************/
/**
* Set parameter of touch sensor filter and detection algorithm.
* For more details on the detection algorithm, please refer to the application documentation.
*
* @param filter_info select filter type and threshold of detection algorithm
*/
void touch_hal_filter_set_config(const touch_filter_config_t *filter_info);
/**
* Get parameter of touch sensor filter and detection algorithm.
* For more details on the detection algorithm, please refer to the application documentation.
*
* @param filter_info select filter type and threshold of detection algorithm
*/
void touch_hal_filter_get_config(touch_filter_config_t *filter_info);
/**
* Get smoothed data that obtained by filtering the raw data.
*
* @param touch_num touch pad index
* @param smooth_data pointer to smoothed data
*/
#define touch_hal_filter_read_smooth(touch_num, smooth_data) touch_ll_filter_read_smooth(touch_num, smooth_data)
/**
* Get benchmark value of touch sensor.
*
* @note After initialization, the benchmark value is the maximum during the first measurement period.
* @param touch_num touch pad index
* @param touch_value pointer to accept touch sensor value
*/
#define touch_hal_read_benchmark(touch_num, benchmark) touch_ll_read_benchmark(touch_num, benchmark)
/**
* Force reset benchmark to raw data of touch sensor.
*
* @param touch_num touch pad index
* - TOUCH_PAD_MAX Reset basaline of all channels.
*/
#define touch_hal_reset_benchmark(touch_num) touch_ll_reset_benchmark(touch_num)
/**
* Set filter mode. The input of the filter is the raw value of touch reading,
* and the output of the filter is involved in the judgment of the touch state.
*
* @param mode Filter mode type. Refer to `touch_filter_mode_t`.
*/
#define touch_hal_filter_set_filter_mode(mode) touch_ll_filter_set_filter_mode(mode)
/**
* Get filter mode. The input of the filter is the raw value of touch reading,
* and the output of the filter is involved in the judgment of the touch state.
*
* @param mode Filter mode type. Refer to `touch_filter_mode_t`.
*/
#define touch_hal_filter_get_filter_mode(mode) touch_ll_filter_get_filter_mode(mode)
/**
* Set debounce count, such as `n`. If the measured values continue to exceed
* the threshold for `n` times, it is determined that the touch sensor state changes.
*
* @param dbc_cnt Debounce count value.
*/
#define touch_hal_filter_set_debounce(dbc_cnt) touch_ll_filter_set_debounce(dbc_cnt)
/**
* Get debounce count.
*
* @param dbc_cnt Debounce count value.
*/
#define touch_hal_filter_get_debounce(dbc_cnt) touch_ll_filter_get_debounce(dbc_cnt)
/**
* Set noise threshold coefficient. Higher = More noise resistance.
* The actual noise should be less than (noise coefficient * touch threshold).
* Range: 0 ~ 3. The coefficient is 0: 4/8; 1: 3/8; 2: 2/8; 3: 1;
*
* @param hys_thr Noise threshold coefficient.
*/
#define touch_hal_filter_set_noise_thres(noise_thr) touch_ll_filter_set_noise_thres(noise_thr)
/**
* Get noise threshold coefficient. Higher = More noise resistance.
* The actual noise should be less than (noise coefficient * touch threshold).
* Range: 0 ~ 3. The coefficient is 0: 4/8; 1: 3/8; 2: 2/8; 3: 1;
*
* @param noise_thr Noise threshold coefficient.
*/
#define touch_hal_filter_get_noise_thres(noise_thr) touch_ll_filter_get_noise_thres(noise_thr)
/**
* Set the cumulative number of benchmark reset processes. such as `n`. If the measured values continue to exceed
* the negative noise threshold for `n` times, the benchmark reset to raw data.
* Range: 0 ~ 15
*
* @param reset_cnt The cumulative number of benchmark reset processes.
*/
#define touch_hal_filter_set_benchmark_reset(reset_cnt) touch_ll_filter_set_benchmark_reset(reset_cnt)
/**
* Get the cumulative number of benchmark reset processes. such as `n`. If the measured values continue to exceed
* the negative noise threshold for `n` times, the benchmark reset to raw data.
* Range: 0 ~ 15
*
* @param reset_cnt The cumulative number of benchmark reset processes.
*/
#define touch_hal_filter_get_benchmark_reset(reset_cnt) touch_ll_filter_get_benchmark_reset(reset_cnt)
/**
* Set jitter filter step size.
* If filter mode is jitter, should set filter step for jitter.
* Range: 0 ~ 15
*
* @param step The step size of the data change.
*/
#define touch_hal_filter_set_jitter_step(step) touch_ll_filter_set_jitter_step(step)
/**
* Get jitter filter step size.
* If filter mode is jitter, should set filter step for jitter.
* Range: 0 ~ 15
*
* @param step The step size of the data change.
*/
#define touch_hal_filter_get_jitter_step(step) touch_ll_filter_get_jitter_step(step)
/**
* Enable touch sensor filter and detection algorithm.
* For more details on the detection algorithm, please refer to the application documentation.
*/
#define touch_hal_filter_enable() touch_ll_filter_enable()
/**
* Disable touch sensor filter and detection algorithm.
* For more details on the detection algorithm, please refer to the application documentation.
*/
#define touch_hal_filter_disable() touch_ll_filter_disable()
/************************ Denoise register setting ************************/
/**
* set parameter of denoise pad (TOUCH_PAD_NUM0).
* T0 is an internal channel that does not have a corresponding external GPIO.
* T0 will work simultaneously with the measured channel Tn. Finally, the actual
* measured value of Tn is the value after subtracting lower bits of T0.
* This denoise function filters out interference introduced on all channels,
* such as noise introduced by the power supply and external EMI.
*
* @param denoise parameter of denoise
*/
void touch_hal_denoise_set_config(const touch_pad_denoise_t *denoise);
/**
* @brief get parameter of denoise pad (TOUCH_PAD_NUM0).
*
* @param denoise Pointer to parameter of denoise
*/
void touch_hal_denoise_get_config(touch_pad_denoise_t *denoise);
/**
* Enable denoise function.
* T0 is an internal channel that does not have a corresponding external GPIO.
* T0 will work simultaneously with the measured channel Tn. Finally, the actual
* measured value of Tn is the value after subtracting lower bits of T0.
* This denoise function filters out interference introduced on all channels,
* such as noise introduced by the power supply and external EMI.
*/
void touch_hal_denoise_enable(void);
/**
* Enable denoise function.
* T0 is an internal channel that does not have a corresponding external GPIO.
* T0 will work simultaneously with the measured channel Tn. Finally, the actual
* measured value of Tn is the value after subtracting lower bits of T0.
* This denoise function filters out interference introduced on all channels,
* such as noise introduced by the power supply and external EMI.
*/
#define touch_hal_denoise_disable() touch_ll_denoise_disable()
/**
* Set internal reference capacitance of denoise channel.
* Select the appropriate internal reference capacitance value so that
* the reading of denoise channel is closest to the reading of the channel being measured.
*
* @param cap_level Capacitance level.
*/
#define touch_hal_denoise_set_cap_level(cap_level) touch_ll_denoise_set_cap_level(cap_level)
/**
* Get internal reference capacitance of denoise channel.
* Select the appropriate internal reference capacitance value so that
* the reading of denoise channel is closest to the reading of the channel being measured.
*
* @param cap_level Capacitance level.
*/
#define touch_hal_denoise_get_cap_level(cap_level) touch_ll_denoise_get_cap_level(cap_level)
/**
* Set denoise range of denoise channel.
* Determined by measuring the noise amplitude of the denoise channel.
*
* @param grade Denoise range of denoise channel.
*/
#define touch_hal_denoise_set_grade(grade) touch_ll_denoise_set_grade(grade)
/**
* Set denoise range of denoise channel.
* Determined by measuring the noise amplitude of the denoise channel.
*
* @param grade Denoise range of denoise channel.
*/
#define touch_hal_denoise_get_grade(grade) touch_ll_denoise_get_grade(grade)
/**
* Read denoise measure value (TOUCH_PAD_NUM0).
*
* @param denoise value of denoise.
*/
#define touch_hal_denoise_read_data(data) touch_ll_denoise_read_data(data)
/************************ Waterproof register setting ************************/
/**
* Set touch channel use for guard pad.
*
* @param pad_num Touch sensor channel number.
*/
#define touch_hal_waterproof_set_guard_pad(pad_num) touch_ll_waterproof_set_guard_pad(pad_num)
/**
* Get touch channel use for guard pad.
*
* @param pad_num Touch sensor channel number.
*/
#define touch_hal_waterproof_get_guard_pad(pad_num) touch_ll_waterproof_get_guard_pad(pad_num)
/**
* Set max equivalent capacitance for sheild channel.
* The equivalent capacitance of the shielded channel can be calculated
* from the reading of denoise channel.
*
* @param pad_num Touch sensor channel number.
*/
#define touch_hal_waterproof_set_sheild_driver(driver_level) touch_ll_waterproof_set_sheild_driver(driver_level)
/**
* Get max equivalent capacitance for sheild channel.
* The equivalent capacitance of the shielded channel can be calculated
* from the reading of denoise channel.
*
* @param pad_num Touch sensor channel number.
*/
#define touch_hal_waterproof_get_sheild_driver(driver_level) touch_ll_waterproof_get_sheild_driver(driver_level)
/**
* Set parameter of waterproof function.
*
* The waterproof function includes a shielded channel (TOUCH_PAD_NUM14) and a guard channel.
* Guard pad is used to detect the large area of water covering the touch panel.
* Shield pad is used to shield the influence of water droplets covering the touch panel.
* It is generally designed as a grid and is placed around the touch buttons.
*
* @param waterproof parameter of waterproof
*/
void touch_hal_waterproof_set_config(const touch_pad_waterproof_t *waterproof);
/**
* Get parameter of waterproof function.
*
* @param waterproof parameter of waterproof.
*/
void touch_hal_waterproof_get_config(touch_pad_waterproof_t *waterproof);
/**
* Enable parameter of waterproof function.
* Should be called after function ``touch_hal_waterproof_set_config``.
*/
void touch_hal_waterproof_enable(void);
/**
* Disable parameter of waterproof function.
*/
#define touch_hal_waterproof_disable() touch_ll_waterproof_disable()
/************************ Proximity register setting ************************/
/**
* Enable/disable proximity function of touch channels.
* The proximity sensor measurement is the accumulation of touch channel measurements.
*
* @note Supports up to three touch channels configured as proximity sensors.
* @param touch_num touch pad index
* @param enabled true: enable the proximity function; false: disable the proximity function
* @return
* - true: Configured correctly.
* - false: Configured error.
*/
bool touch_hal_enable_proximity(touch_pad_t touch_num, bool enabled);
/**
* Set touch channel number for proximity pad.
* If disable the proximity pad, point this pad to `TOUCH_PAD_NUM0`
*
* @param prox_pad The array of three proximity pads.
*/
#define touch_hal_proximity_set_channel_num(prox_pad) touch_ll_proximity_set_channel_num(prox_pad)
/**
* Get touch channel number for proximity pad.
* If disable the proximity pad, point this pad to `TOUCH_PAD_NUM0`
*
* @param prox_pad The array of three proximity pads.
*/
#define touch_hal_proximity_get_channel_num(prox_pad) touch_ll_proximity_get_channel_num(prox_pad)
/**
* Set cumulative measurement times for proximity pad.
*
* @param times The cumulative number of measurement cycles.
*/
#define touch_hal_proximity_set_meas_times(times) touch_ll_proximity_set_meas_times(times)
/**
* Get cumulative measurement times for proximity pad.
*
* @param times The cumulative number of measurement cycles.
*/
#define touch_hal_proximity_get_meas_times(times) touch_ll_proximity_get_meas_times(times)
/**
* Read current cumulative measurement times for proximity pad.
*
* @param times The cumulative number of measurement cycles.
*/
#define touch_hal_proximity_read_meas_cnt(touch_num, cnt) touch_ll_proximity_read_meas_cnt(touch_num, cnt)
/**
* Check if the touch sensor channel is the proximity pad.
*
* @param touch_num The touch sensor channel number.
*/
#define touch_hal_proximity_pad_check(touch_num) touch_ll_proximity_pad_check(touch_num)
/************** sleep pad setting ***********************/
/**
* Get parameter of touch sensor sleep channel.
* The touch sensor can works in sleep mode to wake up sleep.
* After the sleep channel is configured, users should query the channel reading using a specific function.
*
* @param slp_config Point to touch sleep pad config.
*/
void touch_hal_sleep_channel_get_config(touch_pad_sleep_channel_t *slp_config);
/**
* Set parameter of touch sensor sleep channel.
* The touch sensor can works in sleep mode to wake up sleep.
* After the sleep channel is configured, users should query the channel reading using a specific function.
*
* @note ESP32S2 only support one channel to be set sleep channel.
*
* @param pad_num touch sleep pad number.
* @param enable Enable/disable sleep pad function.
*/
void touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable);
/**
* Set touch channel number for sleep pad.
*
* @note Only one touch sensor channel is supported in deep sleep mode.
* @param touch_num Touch sensor channel number.
*/
#define touch_hal_sleep_set_channel_num(touch_num) touch_ll_sleep_set_channel_num(touch_num)
/**
* Get touch channel number for sleep pad.
*
* @note Only one touch sensor channel is supported in deep sleep mode.
* @param touch_num Touch sensor channel number.
*/
#define touch_hal_sleep_get_channel_num(touch_num) touch_ll_sleep_get_channel_num(touch_num)
/**
* Set the trigger threshold of touch sensor in deep sleep.
* The threshold determines the sensitivity of the touch sensor.
* The threshold is the original value of the trigger state minus the benchmark value.
*
* @note The threshold at sleep is the same as the threshold before sleep.
*/
#define touch_hal_sleep_set_threshold(touch_thres) touch_ll_sleep_set_threshold(touch_thres)
/**
* Get the trigger threshold of touch sensor in deep sleep.
* The threshold determines the sensitivity of the touch sensor.
* The threshold is the original value of the trigger state minus the benchmark value.
*
* @note The threshold at sleep is the same as the threshold before sleep.
*/
#define touch_hal_sleep_get_threshold(touch_thres) touch_ll_sleep_get_threshold(touch_thres)
/**
* Enable proximity function for sleep pad.
*/
#define touch_hal_sleep_enable_approach() touch_ll_sleep_enable_approach()
/**
* Disable proximity function for sleep pad.
*/
#define touch_hal_sleep_disable_approach() touch_ll_sleep_disable_approach()
/**
* Read benchmark of touch sensor for sleep pad.
*
* @param benchmark Pointer to accept touch sensor benchmark value.
*/
#define touch_hal_sleep_read_benchmark(benchmark) touch_ll_sleep_read_benchmark(benchmark)
/**
* Read smooth data of touch sensor for sleep pad.
*/
#define touch_hal_sleep_read_smooth(smooth_data) touch_ll_sleep_read_smooth(smooth_data)
/**
* Read raw data of touch sensor for sleep pad.
*/
#define touch_hal_sleep_read_data(raw_data) touch_ll_sleep_read_data(raw_data)
/**
* Reset benchmark of touch sensor for sleep pad.
*/
#define touch_hal_sleep_reset_benchmark() touch_ll_sleep_reset_benchmark()
/**
* Read debounce of touch sensor for sleep pad.
*
* @param debounce Pointer to accept touch sensor debounce value.
*/
#define touch_hal_sleep_read_debounce(debounce) touch_ll_sleep_read_debounce(debounce)
/**
* Read proximity count of touch sensor for sleep pad.
* @param proximity_cnt Pointer to accept touch sensor proximity count value.
*/
#define touch_hal_sleep_read_proximity_cnt(approach_cnt) touch_ll_sleep_read_proximity_cnt(approach_cnt)
/**
* Get the touch pad which caused wakeup from deep sleep.
*
* @param pad_num pointer to touch pad which caused wakeup.
*/
#define touch_hal_get_wakeup_status(pad_num) touch_ll_get_wakeup_status(pad_num)
/**
* Change the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.
* If this function is not called, the working frequency of touch in the deep sleep state is the same as that in the wake-up state.
*
* @param sleep_cycle 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.
* @param meas_times The times of charge and discharge in each measure process of touch channels.
* The timer frequency is 8Mhz. Range: 0 ~ 0xffff.
* Recommended typical value: Modify this value to make the measurement time around 1ms.
*/
void touch_hal_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times);
/**
* Get the operating frequency of touch pad in deep sleep state. Reducing the operating frequency can effectively reduce power consumption.
*
* @param sleep_cycle 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.
* @param meas_times The times of charge and discharge in each measure process of touch channels.
* The timer frequency is 8Mhz. Range: 0 ~ 0xffff.
* Recommended typical value: Modify this value to make the measurement time around 1ms.
*/
void touch_hal_sleep_channel_get_work_time(uint16_t *sleep_cycle, uint16_t *meas_times);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
// 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 "esp_bit_defs.h"
#include "soc/dport_reg.h"
static inline void trace_ll_set_mem_block(int block)
{
DPORT_WRITE_PERI_REG(DPORT_PMS_OCCUPY_3_REG, BIT(block-4));
}

View File

@@ -0,0 +1,667 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The ll is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The Lowlevel layer for TWAI
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "hal/twai_types.h"
#include "soc/twai_periph.h"
/* ------------------------- Defines and Typedefs --------------------------- */
#define TWAI_LL_STATUS_RBS (0x1 << 0) //Receive Buffer Status
#define TWAI_LL_STATUS_DOS (0x1 << 1) //Data Overrun Status
#define TWAI_LL_STATUS_TBS (0x1 << 2) //Transmit Buffer Status
#define TWAI_LL_STATUS_TCS (0x1 << 3) //Transmission Complete Status
#define TWAI_LL_STATUS_RS (0x1 << 4) //Receive Status
#define TWAI_LL_STATUS_TS (0x1 << 5) //Transmit Status
#define TWAI_LL_STATUS_ES (0x1 << 6) //Error Status
#define TWAI_LL_STATUS_BS (0x1 << 7) //Bus Status
#define TWAI_LL_STATUS_MS (0x1 << 8) //Miss Status
#define TWAI_LL_INTR_RI (0x1 << 0) //Receive Interrupt
#define TWAI_LL_INTR_TI (0x1 << 1) //Transmit Interrupt
#define TWAI_LL_INTR_EI (0x1 << 2) //Error Interrupt
//Data overrun interrupt not supported in SW due to HW peculiarities
#define TWAI_LL_INTR_EPI (0x1 << 5) //Error Passive Interrupt
#define TWAI_LL_INTR_ALI (0x1 << 6) //Arbitration Lost Interrupt
#define TWAI_LL_INTR_BEI (0x1 << 7) //Bus Error Interrupt
/*
* The following frame structure has an NEARLY identical bit field layout to
* each byte of the TX buffer. This allows for formatting and parsing frames to
* be done outside of time critical regions (i.e., ISRs). All the ISR needs to
* do is to copy byte by byte to/from the TX/RX buffer. The two reserved bits in
* TX buffer are used in the frame structure to store the self_reception and
* single_shot flags which in turn indicate the type of transmission to execute.
*/
typedef union {
struct {
struct {
uint8_t dlc: 4; //Data length code (0 to 8) of the frame
uint8_t self_reception: 1; //This frame should be transmitted using self reception command
uint8_t single_shot: 1; //This frame should be transmitted using single shot command
uint8_t rtr: 1; //This frame is a remote transmission request
uint8_t frame_format: 1; //Format of the frame (1 = extended, 0 = standard)
};
union {
struct {
uint8_t id[2]; //11 bit standard frame identifier
uint8_t data[8]; //Data bytes (0 to 8)
uint8_t reserved8[2];
} standard;
struct {
uint8_t id[4]; //29 bit extended frame identifier
uint8_t data[8]; //Data bytes (0 to 8)
} extended;
};
};
uint8_t bytes[13];
} __attribute__((packed)) twai_ll_frame_buffer_t;
_Static_assert(sizeof(twai_ll_frame_buffer_t) == 13, "TX/RX buffer type should be 13 bytes");
/* ---------------------------- Mode Register ------------------------------- */
/**
* @brief Enter reset mode
*
* When in reset mode, the TWAI controller is effectively disconnected from the
* TWAI bus and will not participate in any bus activates. Reset mode is required
* in order to write the majority of configuration registers.
*
* @param hw Start address of the TWAI registers
*
* @note Reset mode is automatically entered on BUS OFF condition
*/
static inline void twai_ll_enter_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 1;
}
/**
* @brief Exit reset mode
*
* When not in reset mode, the TWAI controller will take part in bus activities
* (e.g., send/receive/acknowledge messages and error frames) depending on the
* operating mode.
*
* @param hw Start address of the TWAI registers
*
* @note Reset mode must be exit to initiate BUS OFF recovery
*/
static inline void twai_ll_exit_reset_mode(twai_dev_t *hw)
{
hw->mode_reg.rm = 0;
}
/**
* @brief Check if in reset mode
* @param hw Start address of the TWAI registers
* @return true if in reset mode
*/
static inline bool twai_ll_is_in_reset_mode(twai_dev_t *hw)
{
return hw->mode_reg.rm;
}
/**
* @brief Set operating mode of TWAI controller
*
* @param hw Start address of the TWAI registers
* @param mode Operating mode
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_mode(twai_dev_t *hw, twai_mode_t mode)
{
if (mode == TWAI_MODE_NORMAL) { //Normal Operating mode
hw->mode_reg.lom = 0;
hw->mode_reg.stm = 0;
} else if (mode == TWAI_MODE_NO_ACK) { //Self Test Mode (No Ack)
hw->mode_reg.lom = 0;
hw->mode_reg.stm = 1;
} else if (mode == TWAI_MODE_LISTEN_ONLY) { //Listen Only Mode
hw->mode_reg.lom = 1;
hw->mode_reg.stm = 0;
}
}
/* --------------------------- Command Register ----------------------------- */
/**
* @brief Set TX command
*
* Setting the TX command will cause the TWAI controller to attempt to transmit
* the frame stored in the TX buffer. The TX buffer will be occupied (i.e.,
* locked) until TX completes.
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_tx(twai_dev_t *hw)
{
hw->command_reg.tr = 1;
}
/**
* @brief Set single shot TX command
*
* Similar to setting TX command, but the TWAI controller will not automatically
* retry transmission upon an error (e.g., due to an acknowledgement error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_tx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x03; //Set command_reg.tr and command_reg.at simultaneously for single shot transmittion request
}
/**
* @brief Aborts TX
*
* Frames awaiting TX will be aborted. Frames already being TX are not aborted.
* Transmission Complete Status bit is automatically set to 1.
* Similar to setting TX command, but the TWAI controller will not automatically
* retry transmission upon an error (e.g., due to acknowledge error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_abort_tx(twai_dev_t *hw)
{
hw->command_reg.at = 1;
}
/**
* @brief Release RX buffer
*
* Rotates RX buffer to the next frame in the RX FIFO.
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_set_cmd_release_rx_buffer(twai_dev_t *hw)
{
hw->command_reg.rrb = 1;
}
/**
* @brief Clear data overrun
*
* Clears the data overrun status bit
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_set_cmd_clear_data_overrun(twai_dev_t *hw)
{
hw->command_reg.cdo = 1;
}
/**
* @brief Set self reception single shot command
*
* Similar to setting TX command, but the TWAI controller also simultaneously
* receive the transmitted frame and is generally used for self testing
* purposes. The TWAI controller will not ACK the received message, so consider
* using the NO_ACK operating mode.
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_self_rx_request(twai_dev_t *hw)
{
hw->command_reg.srr = 1;
}
/**
* @brief Set self reception request command
*
* Similar to setting the self reception request, but the TWAI controller will
* not automatically retry transmission upon an error (e.g., due to and
* acknowledgement error).
*
* @param hw Start address of the TWAI registers
*
* @note Transmit commands should be called last (i.e., after handling buffer
* release and clear data overrun) in order to prevent the other commands
* overwriting this latched TX bit with 0.
*/
static inline void twai_ll_set_cmd_self_rx_single_shot(twai_dev_t *hw)
{
hw->command_reg.val = 0x12; //Set command_reg.srr and command_reg.at simultaneously for single shot self reception request
}
/* --------------------------- Status Register ------------------------------ */
/**
* @brief Get all status bits
*
* @param hw Start address of the TWAI registers
* @return Status bits
*/
static inline uint32_t twai_ll_get_status(twai_dev_t *hw)
{
return hw->status_reg.val;
}
/**
* @brief Check if RX FIFO overrun status bit is set
*
* @param hw Start address of the TWAI registers
* @return Overrun status bit
*/
static inline bool twai_ll_is_fifo_overrun(twai_dev_t *hw)
{
return hw->status_reg.dos;
}
/**
* @brief Check if previously TX was successful
*
* @param hw Start address of the TWAI registers
* @return Whether previous TX was successful
*/
static inline bool twai_ll_is_last_tx_successful(twai_dev_t *hw)
{
return hw->status_reg.tcs;
}
/* -------------------------- Interrupt Register ---------------------------- */
/**
* @brief Get currently set interrupts
*
* Reading the interrupt registers will automatically clear all interrupts
* except for the Receive Interrupt.
*
* @param hw Start address of the TWAI registers
* @return Bit mask of set interrupts
*/
static inline uint32_t twai_ll_get_and_clear_intrs(twai_dev_t *hw)
{
return hw->interrupt_reg.val;
}
/* ----------------------- Interrupt Enable Register ------------------------ */
/**
* @brief Set which interrupts are enabled
*
* @param hw Start address of the TWAI registers
* @param Bit mask of interrupts to enable
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_enabled_intrs(twai_dev_t *hw, uint32_t intr_mask)
{
hw->interrupt_enable_reg.val = intr_mask;
}
/* ------------------------ Bus Timing Registers --------------------------- */
/**
* @brief Set bus timing
*
* @param hw Start address of the TWAI registers
* @param brp Baud Rate Prescaler
* @param sjw Synchronization Jump Width
* @param tseg1 Timing Segment 1
* @param tseg2 Timing Segment 2
* @param triple_sampling Triple Sampling enable/disable
*
* @note Must be called in reset mode
* @note ESP32S2 brp can be any even number between 2 to 32768
*/
static inline void twai_ll_set_bus_timing(twai_dev_t *hw, uint32_t brp, uint32_t sjw, uint32_t tseg1, uint32_t tseg2, bool triple_sampling)
{
hw->bus_timing_0_reg.brp = (brp / 2) - 1;
hw->bus_timing_0_reg.sjw = sjw - 1;
hw->bus_timing_1_reg.tseg1 = tseg1 - 1;
hw->bus_timing_1_reg.tseg2 = tseg2 - 1;
hw->bus_timing_1_reg.sam = triple_sampling;
}
/* ----------------------------- ALC Register ------------------------------- */
/**
* @brief Clear Arbitration Lost Capture Register
*
* Reading the ALC register rearms the Arbitration Lost Interrupt
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_clear_arb_lost_cap(twai_dev_t *hw)
{
(void)hw->arbitration_lost_captue_reg.val;
}
/* ----------------------------- ECC Register ------------------------------- */
/**
* @brief Clear Error Code Capture register
*
* Reading the ECC register rearms the Bus Error Interrupt
*
* @param hw Start address of the TWAI registers
*/
static inline void twai_ll_clear_err_code_cap(twai_dev_t *hw)
{
(void)hw->error_code_capture_reg.val;
}
/* ----------------------------- EWL Register ------------------------------- */
/**
* @brief Set Error Warning Limit
*
* @param hw Start address of the TWAI registers
* @param ewl Error Warning Limit
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_err_warn_lim(twai_dev_t *hw, uint32_t ewl)
{
hw->error_warning_limit_reg.ewl = ewl;
}
/**
* @brief Get Error Warning Limit
*
* @param hw Start address of the TWAI registers
* @return Error Warning Limit
*/
static inline uint32_t twai_ll_get_err_warn_lim(twai_dev_t *hw)
{
return hw->error_warning_limit_reg.val;
}
/* ------------------------ RX Error Count Register ------------------------- */
/**
* @brief Get RX Error Counter
*
* @param hw Start address of the TWAI registers
* @return REC value
*
* @note REC is not frozen in reset mode. Listen only mode will freeze it. A BUS
* OFF condition automatically sets the REC to 0.
*/
static inline uint32_t twai_ll_get_rec(twai_dev_t *hw)
{
return hw->rx_error_counter_reg.val;
}
/**
* @brief Set RX Error Counter
*
* @param hw Start address of the TWAI registers
* @param rec REC value
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_rec(twai_dev_t *hw, uint32_t rec)
{
hw->rx_error_counter_reg.rxerr = rec;
}
/* ------------------------ TX Error Count Register ------------------------- */
/**
* @brief Get TX Error Counter
*
* @param hw Start address of the TWAI registers
* @return TEC value
*
* @note A BUS OFF condition will automatically set this to 128
*/
static inline uint32_t twai_ll_get_tec(twai_dev_t *hw)
{
return hw->tx_error_counter_reg.val;
}
/**
* @brief Set TX Error Counter
*
* @param hw Start address of the TWAI registers
* @param tec TEC value
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_tec(twai_dev_t *hw, uint32_t tec)
{
hw->tx_error_counter_reg.txerr = tec;
}
/* ---------------------- Acceptance Filter Registers ----------------------- */
/**
* @brief Set Acceptance Filter
* @param hw Start address of the TWAI registers
* @param code Acceptance Code
* @param mask Acceptance Mask
* @param single_filter Whether to enable single filter mode
*
* @note Must be called in reset mode
*/
static inline void twai_ll_set_acc_filter(twai_dev_t* hw, uint32_t code, uint32_t mask, bool single_filter)
{
uint32_t code_swapped = __builtin_bswap32(code);
uint32_t mask_swapped = __builtin_bswap32(mask);
for (int i = 0; i < 4; i++) {
hw->acceptance_filter.acr[i].byte = ((code_swapped >> (i * 8)) & 0xFF);
hw->acceptance_filter.amr[i].byte = ((mask_swapped >> (i * 8)) & 0xFF);
}
hw->mode_reg.afm = single_filter;
}
/* ------------------------- TX/RX Buffer Registers ------------------------- */
/**
* @brief Copy a formatted TWAI frame into TX buffer for transmission
*
* @param hw Start address of the TWAI registers
* @param tx_frame Pointer to formatted frame
*
* @note Call twai_ll_format_frame_buffer() to format a frame
*/
static inline void twai_ll_set_tx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *tx_frame)
{
//Copy formatted frame into TX buffer
for (int i = 0; i < 13; i++) {
hw->tx_rx_buffer[i].val = tx_frame->bytes[i];
}
}
/**
* @brief Copy a received frame from the RX buffer for parsing
*
* @param hw Start address of the TWAI registers
* @param rx_frame Pointer to store formatted frame
*
* @note Call twai_ll_prase_frame_buffer() to parse the formatted frame
*/
static inline void twai_ll_get_rx_buffer(twai_dev_t *hw, twai_ll_frame_buffer_t *rx_frame)
{
//Copy RX buffer registers into frame
for (int i = 0; i < 13; i++) {
rx_frame->bytes[i] = hw->tx_rx_buffer[i].byte;
}
}
/**
* @brief Format contents of a TWAI frame into layout of TX Buffer
*
* This function encodes a message into a frame structure. The frame structure
* has an identical layout to the TX buffer, allowing the frame structure to be
* directly copied into TX buffer.
*
* @param[in] 11bit or 29bit ID
* @param[in] dlc Data length code
* @param[in] data Pointer to an 8 byte array containing data. NULL if no data
* @param[in] format Type of TWAI frame
* @param[in] single_shot Frame will not be retransmitted on failure
* @param[in] self_rx Frame will also be simultaneously received
* @param[out] tx_frame Pointer to store formatted frame
*/
static inline void twai_ll_format_frame_buffer(uint32_t id, uint8_t dlc, const uint8_t *data,
uint32_t flags, twai_ll_frame_buffer_t *tx_frame)
{
bool is_extd = flags & TWAI_MSG_FLAG_EXTD;
bool is_rtr = flags & TWAI_MSG_FLAG_RTR;
//Set frame information
tx_frame->dlc = dlc;
tx_frame->frame_format = is_extd;
tx_frame->rtr = is_rtr;
tx_frame->self_reception = (flags & TWAI_MSG_FLAG_SELF) ? 1 : 0;
tx_frame->single_shot = (flags & TWAI_MSG_FLAG_SS) ? 1 : 0;
//Set ID. The ID registers are big endian and left aligned, therefore a bswap will be required
if (is_extd) {
uint32_t id_temp = __builtin_bswap32((id & TWAI_EXTD_ID_MASK) << 3); //((id << 3) >> 8*(3-i))
for (int i = 0; i < 4; i++) {
tx_frame->extended.id[i] = (id_temp >> (8 * i)) & 0xFF;
}
} else {
uint32_t id_temp = __builtin_bswap16((id & TWAI_STD_ID_MASK) << 5); //((id << 5) >> 8*(1-i))
for (int i = 0; i < 2; i++) {
tx_frame->standard.id[i] = (id_temp >> (8 * i)) & 0xFF;
}
}
uint8_t *data_buffer = (is_extd) ? tx_frame->extended.data : tx_frame->standard.data;
if (!is_rtr) { //Only copy data if the frame is a data frame (i.e not a remote frame)
for (int i = 0; (i < dlc) && (i < TWAI_FRAME_MAX_DLC); i++) {
data_buffer[i] = data[i];
}
}
}
/**
* @brief Parse formatted TWAI frame (RX Buffer Layout) into its constituent contents
*
* @param[in] rx_frame Pointer to formatted frame
* @param[out] id 11 or 29bit ID
* @param[out] dlc Data length code
* @param[out] data Data. Left over bytes set to 0.
* @param[out] format Type of TWAI frame
*/
static inline void twai_ll_prase_frame_buffer(twai_ll_frame_buffer_t *rx_frame, uint32_t *id, uint8_t *dlc,
uint8_t *data, uint32_t *flags)
{
//Copy frame information
*dlc = rx_frame->dlc;
uint32_t flags_temp = 0;
flags_temp |= (rx_frame->frame_format) ? TWAI_MSG_FLAG_EXTD : 0;
flags_temp |= (rx_frame->rtr) ? TWAI_MSG_FLAG_RTR : 0;
flags_temp |= (rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_MSG_FLAG_DLC_NON_COMP : 0;
*flags = flags_temp;
//Copy ID. The ID registers are big endian and left aligned, therefore a bswap will be required
if (rx_frame->frame_format) {
uint32_t id_temp = 0;
for (int i = 0; i < 4; i++) {
id_temp |= rx_frame->extended.id[i] << (8 * i);
}
id_temp = __builtin_bswap32(id_temp) >> 3; //((byte[i] << 8*(3-i)) >> 3)
*id = id_temp & TWAI_EXTD_ID_MASK;
} else {
uint32_t id_temp = 0;
for (int i = 0; i < 2; i++) {
id_temp |= rx_frame->standard.id[i] << (8 * i);
}
id_temp = __builtin_bswap16(id_temp) >> 5; //((byte[i] << 8*(1-i)) >> 5)
*id = id_temp & TWAI_STD_ID_MASK;
}
uint8_t *data_buffer = (rx_frame->frame_format) ? rx_frame->extended.data : rx_frame->standard.data;
//Only copy data if the frame is a data frame (i.e. not a remote frame)
int data_length = (rx_frame->rtr) ? 0 : ((rx_frame->dlc > TWAI_FRAME_MAX_DLC) ? TWAI_FRAME_MAX_DLC : rx_frame->dlc);
for (int i = 0; i < data_length; i++) {
data[i] = data_buffer[i];
}
//Set remaining bytes of data to 0
for (int i = data_length; i < TWAI_FRAME_MAX_DLC; i++) {
data[i] = 0;
}
}
/* ----------------------- RX Message Count Register ------------------------ */
/**
* @brief Get RX Message Counter
*
* @param hw Start address of the TWAI registers
* @return RX Message Counter
*/
static inline uint32_t twai_ll_get_rx_msg_count(twai_dev_t *hw)
{
return hw->rx_message_counter_reg.val;
}
/* ------------------------- Clock Divider Register ------------------------- */
/**
* @brief Set CLKOUT Divider and enable/disable
*
* Configure CLKOUT. CLKOUT is a pre-scaled version of APB CLK. Divider can be
* 1, or any even number from 2 to 490. Set the divider to 0 to disable CLKOUT.
*
* @param hw Start address of the TWAI registers
* @param divider Divider for CLKOUT (any even number from 2 to 490). Set to 0 to disable CLKOUT
*/
static inline void twai_ll_set_clkout(twai_dev_t *hw, uint32_t divider)
{
if (divider >= 2 && divider <= 490) {
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = (divider / 2) - 1;
} else if (divider == 1) {
//Setting the divider reg to max value (255) means a divider of 1
hw->clock_divider_reg.co = 0;
hw->clock_divider_reg.cd = 255;
} else {
hw->clock_divider_reg.co = 1;
hw->clock_divider_reg.cd = 0;
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,871 @@
// 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"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
// The default fifo depth
#define UART_LL_FIFO_DEF_LEN (SOC_UART_FIFO_LEN)
// Get UART hardware instance with giving uart num
#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (&UART1))
#define UART_LL_MIN_WAKEUP_THRESH (2)
#define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask
// Define UART interrupts
typedef enum {
UART_INTR_RXFIFO_FULL = (0x1<<0),
UART_INTR_TXFIFO_EMPTY = (0x1<<1),
UART_INTR_PARITY_ERR = (0x1<<2),
UART_INTR_FRAM_ERR = (0x1<<3),
UART_INTR_RXFIFO_OVF = (0x1<<4),
UART_INTR_DSR_CHG = (0x1<<5),
UART_INTR_CTS_CHG = (0x1<<6),
UART_INTR_BRK_DET = (0x1<<7),
UART_INTR_RXFIFO_TOUT = (0x1<<8),
UART_INTR_SW_XON = (0x1<<9),
UART_INTR_SW_XOFF = (0x1<<10),
UART_INTR_GLITCH_DET = (0x1<<11),
UART_INTR_TX_BRK_DONE = (0x1<<12),
UART_INTR_TX_BRK_IDLE = (0x1<<13),
UART_INTR_TX_DONE = (0x1<<14),
UART_INTR_RS485_PARITY_ERR = (0x1<<15),
UART_INTR_RS485_FRM_ERR = (0x1<<16),
UART_INTR_RS485_CLASH = (0x1<<17),
UART_INTR_CMD_CHAR_DET = (0x1<<18),
} uart_intr_t;
/**
* @brief Set the UART source clock.
*
* @param hw Beginning address of the peripheral registers.
* @param source_clk The UART source clock. The source clock can be APB clock or REF_TICK.
* If the source clock is REF_TICK, the UART can still work when the APB changes.
*
* @return None.
*/
FORCE_INLINE_ATTR void uart_ll_set_sclk(uart_dev_t *hw, uart_sclk_t source_clk)
{
hw->conf0.tick_ref_always_on = (source_clk == UART_SCLK_APB) ? 1 : 0;
}
/**
* @brief Get the UART source clock type.
*
* @param hw Beginning address of the peripheral registers.
* @param source_clk The pointer to accept the UART source clock type.
*
* @return None.
*/
FORCE_INLINE_ATTR 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 Get the UART source clock frequency.
*
* @param hw Beginning address of the peripheral registers.
*
* @return Current source clock frequency
*/
FORCE_INLINE_ATTR uint32_t uart_ll_get_sclk_freq(uart_dev_t *hw)
{
return (hw->conf0.tick_ref_always_on) ? APB_CLK_FREQ : REF_CLK_FREQ;
}
/**
* @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`
* @return None
*/
FORCE_INLINE_ATTR void uart_ll_set_baudrate(uart_dev_t *hw, uint32_t baud)
{
uint32_t sclk_freq, clk_div;
sclk_freq = uart_ll_get_sclk_freq(hw);
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;
}
/**
* @brief Get the current baud-rate.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The current baudrate
*/
FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw)
{
uint32_t sclk_freq = uart_ll_get_sclk_freq(hw);
typeof(hw->clk_div) div_reg = hw->clk_div;
return ((sclk_freq << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag);
}
/**
* @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
*/
FORCE_INLINE_ATTR 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
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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
*/
FORCE_INLINE_ATTR void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask)
{
hw->int_clr.val = mask;
}
/**
* @brief Get status of enabled interrupt.
*
* @param hw Beginning address of the peripheral registers.
*
* @return interrupt enable value
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len)
{
//Get the UART fifo addr, ESP32-S2 have 2 UART
uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1);
for(uint32_t 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
*/
FORCE_INLINE_ATTR void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len)
{
//Get the UART fifo addr, ESP32-S2 have 2 UART
uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1);
for(uint32_t 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
*/
FORCE_INLINE_ATTR void uart_ll_rxfifo_rst(uart_dev_t *hw)
{
hw->conf0.rxfifo_rst = 1;
hw->conf0.rxfifo_rst = 0;
}
/**
* @brief Reset the UART hw txfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None
*/
FORCE_INLINE_ATTR void uart_ll_txfifo_rst(uart_dev_t *hw)
{
hw->conf0.txfifo_rst = 1;
hw->conf0.txfifo_rst = 0;
}
/**
* @brief Get the length of readable data in UART rxfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The readable data length in rxfifo.
*/
FORCE_INLINE_ATTR uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw)
{
return hw->status.rxfifo_cnt;
}
/**
* @brief Get the writable data length of UART txfifo.
*
* @param hw Beginning address of the peripheral registers.
*
* @return The data length of txfifo can be written.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit)
{
hw->conf0.stop_bit_num = stop_bit;
}
/**
* @brief Get the configuration of the UART stop bit.
*
* @param hw Beginning address of the peripheral registers.
* @param stop_bit The pointer to accept the stop bit configuration
*
* @return None.
*/
FORCE_INLINE_ATTR void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit)
{
*stop_bit = hw->conf0.stop_bit_num;
}
/**
* @brief Configure the UART parity check mode.
*
* @param hw Beginning address of the peripheral registers.
* @param parity_mode The parity check mode to be set.
*
* @return None.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs)
{
//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
if(flow_ctrl & UART_HW_FLOWCTRL_RTS) {
hw->mem_conf.rx_flow_thrhd = rx_thrs;
hw->conf1.rx_flow_en = 1;
} else {
hw->conf1.rx_flow_en = 0;
}
if(flow_ctrl & UART_HW_FLOWCTRL_CTS) {
hw->conf0.tx_flow_en = 1;
} else {
hw->conf0.tx_flow_en = 0;
}
}
/**
* @brief Configure the hardware flow control.
*
* @param hw Beginning address of the peripheral registers.
* @param flow_ctrl A pointer to accept the hw flow control configuration.
*
* @return None.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en)
{
if(sw_flow_ctrl_en) {
hw->flow_conf.xonoff_del = 1;
hw->flow_conf.sw_flow_con_en = 1;
hw->swfc_conf1.xon_threshold = flow_ctrl->xon_thrd;
hw->swfc_conf0.xoff_threshold = flow_ctrl->xoff_thrd;
hw->swfc_conf1.xon_char = flow_ctrl->xon_char;
hw->swfc_conf0.xoff_char = flow_ctrl->xoff_char;
} else {
hw->flow_conf.sw_flow_con_en = 0;
hw->flow_conf.xonoff_del = 0;
}
}
/**
* @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt.
*
* @param hw Beginning address of the peripheral registers.
* @param cmd_char The AT cmd char configuration.The configuration member is:
* - cmd_char The AT cmd character
* - char_num The number of received AT cmd char must be equal to or greater than this value
* - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char
* - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char
* - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char
*
* @return None.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit)
{
hw->conf0.bit_num = data_bit;
}
/**
* @brief Set the rts active level.
*
* @param hw Beginning address of the peripheral registers.
* @param level The rts active level, 0 or 1.
*
* @return None.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd)
{
hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH;
}
/**
* @brief Configure the UART work in normal mode.
*
* @param hw Beginning address of the peripheral registers.
*
* @return None.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw)
{
return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH;
}
/**
* @brief Get the UART data bit configuration.
*
* @param hw Beginning address of the peripheral registers.
* @param data_bit The pointer to accept the UART data bit configuration.
*
* @return The bit mode.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR bool uart_ll_is_tx_idle(uart_dev_t *hw)
{
return ((hw->status.txfifo_cnt == 0) && (hw->fsm_status.st_utx_out == 0));
}
/**
* @brief Check if the UART rts flow control is enabled.
*
* @param hw Beginning address of the peripheral registers.
*
* @return True if hw rts flow control is enabled, otherwise false is returned.
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR 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
*/
FORCE_INLINE_ATTR 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.
*/
FORCE_INLINE_ATTR void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask)
{
typeof(hw->conf0) conf0_reg = hw->conf0;
conf0_reg.irda_tx_inv = (inv_mask & UART_SIGNAL_IRDA_TX_INV) ? 1 : 0;
conf0_reg.irda_rx_inv = (inv_mask & UART_SIGNAL_IRDA_RX_INV) ? 1 : 0;
conf0_reg.rxd_inv = (inv_mask & UART_SIGNAL_RXD_INV) ? 1 : 0;
conf0_reg.cts_inv = (inv_mask & UART_SIGNAL_CTS_INV) ? 1 : 0;
conf0_reg.dsr_inv = (inv_mask & UART_SIGNAL_DSR_INV) ? 1 : 0;
conf0_reg.txd_inv = (inv_mask & UART_SIGNAL_TXD_INV) ? 1 : 0;
conf0_reg.rts_inv = (inv_mask & UART_SIGNAL_RTS_INV) ? 1 : 0;
conf0_reg.dtr_inv = (inv_mask & UART_SIGNAL_DTR_INV) ? 1 : 0;
hw->conf0.val = conf0_reg.val;
}
/**
* @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function.
*
* @param hw Beginning address of the peripheral registers.
* @param tout_thrd The timeout value as UART bit time. The rx timeout function will be disabled if `tout_thrd == 0`.
*
* @return None.
*/
FORCE_INLINE_ATTR void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd)
{
uint16_t tout_val = tout_thrd;
if(tout_thrd > 0) {
hw->mem_conf.rx_tout_thrhd = tout_val;
hw->conf1.rx_tout_en = 1;
} else {
hw->conf1.rx_tout_en = 0;
}
}
/**
* @brief Get the timeout value for receiver receiving a byte.
*
* @param hw Beginning address of the peripheral registers.
*
* @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0.
*/
FORCE_INLINE_ATTR uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw)
{
uint16_t tout_thrd = 0;
if(hw->conf1.rx_tout_en > 0) {
tout_thrd = hw->mem_conf.rx_tout_thrhd;
}
return tout_thrd;
}
/**
* @brief Get UART maximum timeout threshold.
*
* @param hw Beginning address of the peripheral registers.
*
* @return maximum timeout threshold.
*/
FORCE_INLINE_ATTR uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw)
{
return UART_RX_TOUT_THRHD_V;
}
/**
* @brief Force UART xoff.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return None.
*/
FORCE_INLINE_ATTR void uart_ll_force_xoff(uart_port_t uart_num)
{
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XOFF);
}
/**
* @brief Force UART xon.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return None.
*/
FORCE_INLINE_ATTR void uart_ll_force_xon(uart_port_t uart_num)
{
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XOFF);
REG_SET_BIT(UART_FLOW_CONF_REG(uart_num), UART_FORCE_XON);
REG_CLR_BIT(UART_FLOW_CONF_REG(uart_num), UART_SW_FLOW_CON_EN | UART_FORCE_XON);
}
/**
* @brief Get UART final state machine status.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return UART module FSM status.
*/
FORCE_INLINE_ATTR uint32_t uart_ll_get_fsm_status(uart_port_t uart_num)
{
return REG_GET_FIELD(UART_FSM_STATUS_REG(uart_num), UART_ST_UTX_OUT);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,42 @@
// 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 "soc/soc.h"
#include "soc/system_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h"
static inline void usb_ll_int_phy_enable(void)
{
USB_WRAP.otg_conf.pad_enable = 1;
USB_WRAP.otg_conf.phy_sel = 0;
}
static inline void usb_ll_ext_phy_enable(void)
{
USB_WRAP.otg_conf.pad_enable = 1;
USB_WRAP.otg_conf.phy_sel = 1;
}
static inline void usb_ll_int_phy_pullup_conf(bool dp_pu, bool dp_pd, bool dm_pu, bool dm_pd)
{
usb_wrap_otg_conf_reg_t conf = USB_WRAP.otg_conf;
conf.pad_pull_override = 1;
conf.dp_pullup = dp_pu;
conf.dp_pulldown = dp_pd;
conf.dm_pullup = dm_pu;
conf.dm_pulldown = dp_pd;
USB_WRAP.otg_conf = conf;
}

View File

@@ -0,0 +1,805 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/*
NOTE: Thread safety is the responsibility fo the HAL user. All USB Host HAL
functions should be called from critical sections unless specified otherwise
*/
#include <stdlib.h>
#include <stddef.h>
#include "soc/usbh_struct.h"
#include "soc/usb_wrap_struct.h"
#include "hal/usbh_ll.h"
#include "hal/usb_types.h"
/* -----------------------------------------------------------------------------
------------------------------- Macros and Types -------------------------------
----------------------------------------------------------------------------- */
// ---------------------------- Constants/Configs ------------------------------
#define USBH_HAL_DMA_MEM_ALIGN 512
#define USBH_HAL_NUM_CHAN 8
#define USBH_HAL_XFER_DESC_SIZE (sizeof(usbh_ll_dma_qtd_t))
// ------------------------------- HAL States ----------------------------------
/**
* @brief Channel states
*
*/
typedef enum {
USBH_HAL_CHAN_STATE_HALTED = 0, /**< The channel is halted. No transfer descriptor list is being executed */
USBH_HAL_CHAN_STATE_ACTIVE, /**< The channel is active. A transfer descriptor list is being executed */
USBH_HAL_CHAN_STATE_ERROR, /**< The channel is in the error state */
} usbh_hal_chan_state_t;
// ------------------------------- HAL Events ----------------------------------
/**
* @brief Host port HAL events
*/
typedef enum {
USBH_HAL_PORT_EVENT_NONE, /**< No event occurred, or could not decode interrupt */
USBH_HAL_PORT_EVENT_CHAN, /**< A channel event has occurred. Call the the channel event handler instead */
USBH_HAL_PORT_EVENT_CONN, /**< The host port has detected a connection */
USBH_HAL_PORT_EVENT_DISCONN, /**< The host port has been disconnected */
USBH_HAL_PORT_EVENT_ENABLED, /**< The host port has been enabled (i.e., connected to a device that has been reset. Started sending SOFs) */
USBH_HAL_PORT_EVENT_DISABLED, /**< The host port has been disabled (no more SOFs). Could be due to disable/reset request, or a port error (e.g. port babble condition. See 11.8.1 of USB2.0 spec) */
USBH_HAL_PORT_EVENT_OVRCUR, /**< The host port has encountered an overcurrent condition */
USBH_HAL_PORT_EVENT_OVRCUR_CLR, /**< The host port has been cleared of the overcurrent condition */
} usbh_hal_port_event_t;
/**
* @brief Channel events
*/
typedef enum {
USBH_HAL_CHAN_EVENT_SLOT_DONE, /**< The channel has completed execution of an entire transfer descriptor list. Channel is now halted */
USBH_HAL_CHAN_EVENT_SLOT_HALT, /**< The channel as completed execution of a single transfer descriptor in a list. Channel is now halted */
USBH_HAL_CHAN_EVENT_ERROR, /**< The channel has encountered an error. Channel is now halted. */
USBH_HAL_CHAN_EVENT_HALT_REQ, /**< The channel has been successfully halted as requested */
} usbh_hal_chan_event_t;
// ------------------------------- HAL Errors ----------------------------------
/**
* @brief Channel errors
*/
typedef enum {
USBH_HAL_CHAN_ERROR_XCS_XACT = 0, /**< Excessive (three consecutive) transaction errors (e.g., no response, bad CRC etc */
USBH_HAL_CHAN_ERROR_BNA, /**< Buffer Not Available error (i.e., transfer slot is unfilled */
USBH_HAL_CHAN_ERROR_PKT_BBL, /**< Packet babbler error (packet exceeded MPS) */
USBH_HAL_CHAN_ERROR_STALL, /**< STALL response received */
} usbh_hal_chan_error_t;
// ----------------------- Transfer Descriptor Related -------------------------
/**
* @brief Flags used to describe the type of transfer descriptor to fill
*/
#define USBH_HAL_XFER_DESC_FLAG_IN 0x01
#define USBH_HAL_XFER_DESC_FLAG_SETUP 0x02
#define USBH_HAL_XFER_DESC_FLAG_NULL 0x04
#define USBH_HAL_XFER_DESC_FLAG_HALT 0x08
/**
* @brief Status value of a transfer descriptor
*
* A transfer descriptor's status remains unexecuted until the entire transfer
* descriptor completes (either successfully or an error). Therefore, if a
* channel halt is requested before a transfer descriptor completes, the
* transfer descriptoor remains unexecuted.
*/
#define USBH_HAL_XFER_DESC_STS_SUCCESS USBH_LL_QTD_STATUS_SUCCESS
#define USBH_HAL_XFER_DESC_STS_PKTERR USBH_LL_QTD_STATUS_PKTERR
#define USBH_HAL_XFER_DESC_STS_BUFFER_ERR USBH_LL_QTD_STATUS_BUFFER
#define USBH_HAL_XFER_DESC_STS_NOT_EXECUTED USBH_LL_QTD_STATUS_NOT_EXECUTED
// ------------------------------ Object Types ---------------------------------
/**
* @brief Endpoint characteristics structure
*/
typedef struct {
union {
struct {
usb_xfer_type_t type: 2; /**< The type of endpoint */
uint32_t bEndpointAddress: 8; /**< Endpoint address (containing endpoint number and direction) */
uint32_t mps: 11; /**< Maximum Packet Size */
uint32_t dev_addr: 8; /**< Device Address */
uint32_t ls_via_fs_hub: 1; /**< The endpoint is on a LS device that is routed through an FS hub.
Setting this bit will lead to the addition of the PREamble packet */
uint32_t reserved2: 2;
};
uint32_t val;
};
} usbh_hal_ep_char_t;
/**
* @brief Channel object
*/
typedef struct {
//Channel control, status, and information
union {
struct {
uint32_t active: 1; /**< The channel is enabled */
uint32_t halt_requested: 1; /**< A halt has been requested */
uint32_t error_pending: 1; /**< The channel is waiting for the error to be handled */
uint32_t chan_idx: 4; /**< The index number of the channel */
uint32_t reserved25: 25;
};
uint32_t val;
} flags; /**< Flags regarding channel's status and information */
usb_host_chan_regs_t *regs; /**< Pointer to the channel's register set */
usbh_hal_chan_error_t error; /**< The last error that occurred on the channel */
void *chan_ctx; /**< Context variable for the owner of the channel */
//Transfer Descriptor List Slot
struct {
union {
struct {
uint32_t slot_acquired: 1; /**< The transfer descriptor list slot has been acquired */
uint32_t reserved7: 7;
uint32_t cur_qtd_idx: 8; /**< Index of the first QTD in chain of QTDs being executed */
uint32_t qtd_list_len: 8; /**< Length of QTD list in number of QTDs */
uint32_t reserved8: 8;
};
uint32_t val;
} flags;
void *owner_ctx; /**< Context variable for the owner of the slot */
usbh_ll_dma_qtd_t *xfer_desc_list; /**< Pointer to transfer descriptor list */
} slot;
} usbh_hal_chan_t;
/**
* @brief HAL context structure
*/
typedef struct {
//Context
usbh_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */
usb_wrap_dev_t *wrap_dev; /**< Pointer to base address of USB Wrapper registers */
//Host Port related
union {
struct {
uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */
uint32_t reserved31: 31;
};
uint32_t val;
} flags;
//Channel related
struct {
int num_allocd; /**< Number of channels currently allocated */
uint32_t chan_pend_intrs_msk; /**< Bit mask of channels with pending interrupts */
usbh_hal_chan_t *hdls[USBH_HAL_NUM_CHAN]; /**< Handles of each channel. Set to NULL if channel has not been allocated */
} channels;
} usbh_hal_context_t;
/* -----------------------------------------------------------------------------
--------------------------------- Core (Global) --------------------------------
----------------------------------------------------------------------------- */
/**
* @brief Initialize the HAL context and check if DWC_OTG is alive
*
* Entry:
* - The peripheral must have been reset and clock un-gated
* - GPIO pins configured
* - Interrupt allocated but DISABLED (in case of an unknown interupt state)
* Exit:
* - Checks to see if DWC_OTG is alive, and if HW version/config is correct
* - HAl context initialized
* - Sets default values to some global and OTG registers (GAHBCFG and GUSBCFG)
* - Umask global interrupt signal
* - Put DWC_OTG into host mode. Require 25ms delay before this takes effect.
* - State -> USBH_HAL_PORT_STATE_OTG
* - Interrupts cleared. Users can now enable their ISR
*
* @param[inout] hal Context of the HAL layer
*/
void usbh_hal_init(usbh_hal_context_t *hal);
/**
* @brief Deinitialize the HAL context
*
* Entry:
* - All channels should be properly disabled, and any pending events handled
* Exit:
* - DWC_OTG global interrupt disabled
* - HAL context deinitialized
*
* @param hal Context of the HAL layer
*/
void usbh_hal_deinit(usbh_hal_context_t *hal);
/**
* @brief Issue a soft reset to the controller
*
* This should be called when the host port encounters an error event or has
* been disconnected. Before calling this, users are responsible for safely
* freeing all channels as a soft reset will wipe all host port nd channel
* registers.
*
* This function will result in the host port being put back into same state as
* after calling usbh_hal_init().
*
* @note This has nothing to do with a USB bus reset. It simply resets the peripheral
*
* @param hal Context of the HAL layer
*/
void usbh_hal_core_soft_reset(usbh_hal_context_t *hal);
/* -----------------------------------------------------------------------------
---------------------------------- Host Port ----------------------------------
----------------------------------------------------------------------------- */
// ---------------------------- Host Port Control ------------------------------
/**
* @brief Enable the host port's interrupt allowing port and channel events to occur
*
* @param hal Context of the HAL layer
*/
static inline void usbh_hal_port_start(usbh_hal_context_t *hal)
{
//Configure Host related interrupts
usbh_ll_haintmsk_dis_chan_intr(hal->dev, 0xFFFFFFFF); //Disable interrupts for all channels
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
}
/**
* @brief Disable the host port's interrupt preventing any further port or channel events
*
* @param hal Context of the HAL layer
*/
static inline void usbh_hal_port_stop(usbh_hal_context_t *hal)
{
//Disable Host port and channel interrupts
usb_ll_dis_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
}
/**
* @brief Toggle the host port's power
*
* @param hal Context of the HAL layer
* @param power_on Whether to power ON or OFF the port
*/
static inline void usbh_hal_port_toggle_power(usbh_hal_context_t *hal, bool power_on)
{
if (power_on) {
usbh_ll_hprt_en_pwr(hal->dev);
} else {
usbh_ll_hprt_dis_pwr(hal->dev);
}
}
/**
* @brief Toggle reset signal on the bus
*
* The reset signal should be held for at least 10ms
* Entry:
* - Host port detects a device connection or Host port is already enabled
* Exit:
* - On release of the reset signal, a USBH_HAL_PORT_EVENT_ENABLED will be generated
*
* @note If the host port is already enabled, then issuing a reset will cause
* it be disabled and generate a USBH_HAL_PORT_EVENT_DISABLED event. The
* host port will not be enabled until the reset signal is released (thus
* generating the USBH_HAL_PORT_EVENT_ENABLED event)
*
* @param hal Context of the HAL layer
* @param enable Enable/disable reset signal
*/
static inline void usbh_hal_port_toggle_reset(usbh_hal_context_t *hal, bool enable)
{
assert(hal->channels.num_allocd == 0); //Cannot reset if there are still allocated channels
usbh_ll_hprt_set_port_reset(hal->dev, enable);
}
/**
* @brief Enable the host port
*
* Entry:
* - Host port enabled event triggered following a reset
* Exit:
* - Host port enabled to operate in scatter/gather DMA mode
* - DMA fifo sizes configured
*
* @param hal Context of the HAL layer
*/
void usbh_hal_port_enable(usbh_hal_context_t *hal);
/**
* @brief Disable the host port
*
* Exit:
* - Host port disabled event triggered
*
* @param hal Context of the HAL layer
*/
static inline void usbh_hal_port_disable(usbh_hal_context_t *hal)
{
usbh_ll_hprt_port_dis(hal->dev);
}
/**
* @brief Suspend the host port
*
* @param hal Context of the HAL layers
*/
static inline void usbh_hal_port_suspend(usbh_hal_context_t *hal)
{
usbh_ll_hprt_set_port_suspend(hal->dev);
}
/**
* @brief Toggle resume signal on the bus
*
* Hosts should hold the resume signal for at least 20ms
*
* @note If a remote wakeup event occurs, the resume signal is driven
* and cleared automatically.
*
* @param hal Context of the HAL layer
* @param enable Enable/disable resume signal
*/
static inline void usbh_hal_port_toggle_resume(usbh_hal_context_t *hal, bool enable)
{
if (enable) {
usbh_ll_hprt_set_port_resume(hal->dev);
} else {
usbh_ll_hprt_clr_port_resume(hal->dev);
}
}
/**
* @brief Check whether the resume signal is being driven
*
* If a remote wakeup event occurs, the core will automatically drive and clear
* the resume signal for the required amount of time. Call this function to
* check whether the resume signal has completed.
*
* @param hal Context of the HAL layer
* @return true Resume signal is still being driven
* @return false Resume signal is no longer driven
*/
static inline bool usbh_hal_port_check_resume(usbh_hal_context_t *hal)
{
return usbh_ll_hprt_get_port_resume(hal->dev);
}
// -------------------------- Host Port Status/State ---------------------------
/**
* @brief Check if a device is currently connected to the host port
*
* This function is intended to be called after one of the following events
* followed by an adequate debounce delay
* - USBH_HAL_PORT_EVENT_CONN
* - USBH_HAL_PORT_EVENT_DISCONN
*
* @note No other connection/disconnection event will occur again until the
* debounce lock is disabled via usbh_hal_disable_debounce_lock()
*
* @param hal Context of the HAL layer
* @return true A device is connected to the host port
* @return false A device is not connected to the host port
*/
static inline bool usbh_hal_port_check_if_connected(usbh_hal_context_t *hal)
{
return usbh_ll_hprt_get_conn_status(hal->dev);
}
/**
* @brief Check the speed (LS/FS) of the device connected to the host port
*
* @note This function should only be called after confirming that a device is
* connected to the host port
*
* @param hal Context of the HAL layer
* @return usb_speed_t Speed of the connected device
*/
static inline usb_speed_t usbh_hal_port_get_conn_speed(usbh_hal_context_t *hal)
{
return usbh_ll_hprt_get_speed(hal->dev);
}
/**
* @brief Disable the debounce lock
*
* This function should be called after calling usbh_hal_port_check_if_connected()
* and will allow connection/disconnection events to occur again. Any pending
* connection or disconenction interrupts are cleared.
*
* @param hal Context of the HAL layer
*/
static inline void usbh_hal_disable_debounce_lock(usbh_hal_context_t *hal)
{
hal->flags.dbnc_lock_enabled = 0;
//Clear Conenction and disconenction interrupt in case it triggered again
usb_ll_intr_clear(hal->dev, USB_LL_INTR_CORE_DISCONNINT);
usbh_ll_hprt_intr_clear(hal->dev, USBH_LL_INTR_HPRT_PRTENCHNG);
//Reenable the hprt (connection) and disconnection interrupts
usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_DISCONNINT);
}
/* -----------------------------------------------------------------------------
----------------------------------- Channel ------------------------------------
------------------------------------------------------------------------------*/
// --------------------------- Channel Allocation ------------------------------
/**
* @brief Allocate a channel
*
* @param[in] hal Context of the HAL layer
* @param[inout] chan_obj Empty channel object
* @param[in] chan_ctx Context variable for the allocator of the channel
* @return true Channel successfully allocated
* @return false Failed to allocate channel
*/
bool usbh_hal_chan_alloc(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj, void *chan_ctx);
/**
* @brief Free a channel
*
* @param[in] hal Context of the HAL layer
* @param[in] chan_obj Channel object
*/
void usbh_hal_chan_free(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj);
/**
* @brief Get the context variable of the channel
*
* @param[in] chan_obj Channel object
* @return void* The context variable of the channel
*/
static inline void *usbh_hal_chan_get_context(usbh_hal_chan_t *chan_obj)
{
return chan_obj->chan_ctx;
}
// ---------------------------- Channel Control --------------------------------
/**
* @brief Get the current state of a channel
*
* @param chan_obj Channel object
* @return usbh_hal_chan_state_t State of the channel
*/
static inline usbh_hal_chan_state_t usbh_hal_chan_get_state(usbh_hal_chan_t *chan_obj)
{
if (chan_obj->flags.error_pending) {
return USBH_HAL_CHAN_STATE_ERROR;
} else if (chan_obj->flags.active) {
return USBH_HAL_CHAN_STATE_ACTIVE;
} else {
return USBH_HAL_CHAN_STATE_HALTED;
}
}
/**
* @brief Set the endpoint information for a particular channel
*
* This should be called when a channel switches target from one EP to another
*
* @note the channel must be in the disabled state in order to change its EP
* information
*
* @param chan_obj Channel object
* @param ep_char Endpoint characteristics
*/
void usbh_hal_chan_set_ep_char(usbh_hal_chan_t *chan_obj, usbh_hal_ep_char_t *ep_char);
/**
* @brief Set the direction of the channel
*
* This is a convenience function to flip the direction of a channel without
* needing to reconfigure all of the channel's EP info. This is used primarily
* for control transfers.
*
* @note This function should only be called when the channel is in the disabled
* state or is halted from a USBH_HAL_CHAN_EVENT_SLOT_HALT event
*
* @param chan_obj Channel object
* @param is_in Whether the direction is IN
*/
static inline void usbh_hal_chan_set_dir(usbh_hal_chan_t *chan_obj, bool is_in)
{
//Cannot change direction whilst channel is still active or in error
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
usbh_ll_chan_set_dir(chan_obj->regs, is_in);
}
/**
* @brief Set the next Packet ID of the channel (e.g., DATA0/DATA1)
*
* This should be called when a channel switches target from one EP to another
* or when change stages for a control transfer
*
* @note The channel should only be called when the channel is in the
* halted state.
*
* @param chan_obj Channel object
* @param pid PID of the next DATA packet (DATA0 or DATA1)
*/
static inline void usbh_hal_chan_set_pid(usbh_hal_chan_t *chan_obj, int pid)
{
//Cannot change pid whilst channel is still active or in error
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
//Update channel object and set the register
usbh_ll_chan_set_pid(chan_obj->regs, pid);
}
/**
* @brief Get the next PID of a channel
*
* Returns the next PID (DATA0 or DATA1) of the channel. This function should be
* used when the next PID of a pipe needs to be saved (e.g., when switching pipes
* on a channel)
*
* @param chan_obj Channel object
* @return uint32_t Starting PID of the next transfer (DATA0 or DATA1)
*/
static inline uint32_t usbh_hal_chan_get_pid(usbh_hal_chan_t *chan_obj)
{
assert(!chan_obj->flags.active && !chan_obj->flags.error_pending);
return usbh_ll_chan_get_pid(chan_obj->regs);
}
/**
* @brief Get a channel's error
*
* @param chan_obj Channel object
* @return usbh_hal_chan_error_t The type of error the channel has encountered
*/
static inline usbh_hal_chan_error_t usbh_hal_chan_get_error(usbh_hal_chan_t *chan_obj)
{
assert(chan_obj->flags.error_pending);
return chan_obj->error;
}
/**
* @brief Clear a channel of it's error
*
* @param chan_obj Channel object
*/
static inline void usbh_hal_chan_clear_error(usbh_hal_chan_t *chan_obj)
{
//Can only clear error when an error has occurred
assert(chan_obj->flags.error_pending);
chan_obj->flags.error_pending = 0;
}
/* -----------------------------------------------------------------------------
-------------------------- Transfer Descriptor List ----------------------------
------------------------------------------------------------------------------*/
/**
* @brief Fill a single entry in a transfer descriptor list
*
* - A single entry corresponds to a USB transfer in a particular direction
* (e.g., a BULK OUT).
* - The channel will automatically split the transfer into multiple MPS sized
* packets of the endpoint.
* - For multi direction transfers (such as the various stages of a control transfer),
* the direction and PID of channel must be managed manually. Set the
* USBH_HAL_XFER_DESC_FLAG_HALT flag to halt on each entry to flip the direction
* and PID of the channel.
* - For IN transfer entries, set the USBH_HAL_XFER_DESC_FLAG_IN. The transfer
* size must also be an integer multiple of the endpoint's MPS
*
* @note The USBH_HAL_XFER_DESC_FLAG_HALT must be set on the last descriptor of
* the list so that an interrupt is generated at the end of the list
* @note The USBH_HAL_XFER_DESC_FLAG_HALT can be set on every descriptor if users
* prefer to manually step through the list (such as change EP directions in between)
* @note Critical section is not required for this function
*
* @param xfer_desc_list Transfer descriptor list
* @param xfer_desc_idx Transfer descriptor index
* @param xfer_data_buff Transfer data buffer
* @param xfer_len Transfer length
* @param flags Transfer flags
*/
static inline void usbh_hal_xfer_desc_fill(void *xfer_desc_list, int xfer_desc_idx, uint8_t *xfer_data_buff, int xfer_len, uint32_t flags)
{
//Check if the channel should be halted on completion of this xfer descriptor
bool halt_on_xfer_cplt = flags & USBH_HAL_XFER_DESC_FLAG_HALT;
usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)xfer_desc_list;
if (flags & USBH_HAL_XFER_DESC_FLAG_NULL) {
usbh_ll_set_qtd_null(&qtd_list[xfer_desc_idx]);
} else if (flags & USBH_HAL_XFER_DESC_FLAG_IN) {
usbh_ll_set_qtd_in(&qtd_list[xfer_desc_idx], xfer_data_buff, xfer_len, halt_on_xfer_cplt);
} else {
usbh_ll_set_qtd_out(&qtd_list[xfer_desc_idx], xfer_data_buff, xfer_len, halt_on_xfer_cplt, (flags & USBH_HAL_XFER_DESC_FLAG_SETUP));
}
}
/**
* @brief Parse a transfer decriptors results
*
* @param xfer_desc_list Transfer descriptor list
* @param xfer_desc_idx Transfer descriptor index
* @param[out] xfer_rem_len Remaining length of the transfer in bytes
* @param[out] xfer_status Status of the transfer
*
* @note Critical section is not required for this function
*/
static inline void usbh_hal_xfer_desc_parse(void *xfer_desc_list, int xfer_desc_idx, int *xfer_rem_len, int *xfer_status)
{
usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)xfer_desc_list;
usbh_ll_get_qtd_status(&qtd_list[xfer_desc_idx], xfer_rem_len, xfer_status);
}
/* -----------------------------------------------------------------------------
-------------------------------- Channel Slot ----------------------------------
------------------------------------------------------------------------------*/
/**
* @brief Acquire a slot
*
* Acquiring a channel's transfer descriptor list slot will cause a give ownership
* of the channel to the acquirer. The transfer descriptor list to be executed
* when the channel is activated.
*
* @param chan_obj Channel object
* @param xfer_desc_list A filled transfer descriptor list
* @param desc_list_len Length of the descriptor list
* @param owner_ctx Context variable of the owner
*/
static inline void usbh_hal_chan_slot_acquire(usbh_hal_chan_t *chan_obj, void *xfer_desc_list, int desc_list_len, void *owner_ctx)
{
assert(!chan_obj->slot.flags.slot_acquired);
chan_obj->slot.xfer_desc_list = (usbh_ll_dma_qtd_t *)xfer_desc_list;
chan_obj->slot.owner_ctx = owner_ctx;
chan_obj->slot.flags.cur_qtd_idx = 0; //Start from the first descriptor
chan_obj->slot.flags.qtd_list_len = desc_list_len;
chan_obj->slot.flags.slot_acquired = 1;
//Store the descriptor list length in the HCTSIZ register. Address of desc list is set when channel is activated
usbh_ll_chan_set_qtd_list_len(chan_obj->regs, desc_list_len);
}
/**
* @brief Get current owner of a slot
*
* This function reqturns a slot's context variable that was set when the slot
* was acquired
*
* @param chan_obj Channel object
* @return void* Context variable of the owner of the slot
*/
static inline void *usbh_hal_chan_slot_get_owner(usbh_hal_chan_t *chan_obj)
{
assert(chan_obj->slot.flags.slot_acquired);
return chan_obj->slot.owner_ctx;
}
/**
* @brief Release a slot
*
* @note This should only be called after confirming that the transfer descriptor
* list has completed execution.
* @note Users should parse the completed transfer descriptor list to check the
* results of each transfer.
*
* @param[in] chan_obj Channel object
* @param[out] xfer_desc_list A completed transfer descriptor list
* @param[out] desc_list_len Length of the descriptor list
*/
static inline void usbh_hal_chan_slot_release(usbh_hal_chan_t *chan_obj, void **xfer_desc_list, int *desc_list_len)
{
assert(chan_obj->slot.flags.slot_acquired);
*xfer_desc_list = (void *)chan_obj->slot.xfer_desc_list;
*desc_list_len = chan_obj->slot.flags.qtd_list_len;
chan_obj->slot.flags.slot_acquired = 0;
}
/**
* @brief Activate a channel
*
* Activating a channel will cause it to start executing the transfer descriptor
* list in its slot starting from its next descriptor index. When a transfer
* descriptor completes execution and has the HALT flag set, an event will be
* generated.
*
* @param chan_obj Channel object
* @param num_to_skip Number of transfer descriptors to skip over
*/
void usbh_hal_chan_activate(usbh_hal_chan_t *chan_obj, int num_to_skip);
/**
* @brief Get next transfer descriptor index
*
* This function returns the index of the next descriptor that will be executed
* in the transfer descriptor list.
*
* @param chan_obj Channel object
* @return int Descriptor index
*/
static inline int usbh_hal_chan_get_next_desc_index(usbh_hal_chan_t *chan_obj)
{
return chan_obj->slot.flags.cur_qtd_idx;
}
/**
* @brief Request to halt a channel
*
* This function should be called in order to halt a channel. If the channel is
* already halted, this function will return true. If the channel is still
* active, this function will return false and users must wait for the
* USBH_HAL_CHAN_EVENT_HALT_REQ event before treating the channel as halted.
*
* @note When a transfer is in progress (i.e., the channel is active) and a halt
* is requested, the channel will halt after the next USB packet is completed.
* If the transfer has more pending packets, the transfer will just be
* marked as USBH_HAL_XFER_DESC_STS_NOT_EXECUTED.
*
* @param chan_obj Channel object
* @return true The channel is already halted
* @return false The halt was requested, wait for USBH_HAL_CHAN_EVENT_HALT_REQ
*/
bool usbh_hal_chan_slot_request_halt(usbh_hal_chan_t *chan_obj);
/* -----------------------------------------------------------------------------
-------------------------------- Event Handling --------------------------------
----------------------------------------------------------------------------- */
/**
* @brief Decode global and host port interrupts
*
* - Reads and clears global and host port interrupt registers
* - Decodes the interrupt bits to determine what host port event occurred
*
* @note This should be the first interrupt decode function to be run
*
* @param hal Context of the HAL layer
* @return usbh_hal_port_event_t Host port event
*/
usbh_hal_port_event_t usbh_hal_decode_intr(usbh_hal_context_t *hal);
/**
* @brief Gets the next channel with a pending interrupt
*
* If no channel is pending an interrupt, this function will return NULL. If one
* or more channels are pending an interrupt, this function returns one of the
* channel's objects. Call this function repeatedly until it returns NULL.
*
* @note If a channel error event occurs, or a Slot halt/done event occurs, the
* channel is immediately halted and no further channel interrupt or errors
* can occur until it is reactivated.
*
* @param hal Context of the HAL layer
* @return usbh_hal_chan_t* Channel object. NULL if no channel are pending an interrupt.
*/
usbh_hal_chan_t *usbh_hal_get_chan_pending_intr(usbh_hal_context_t *hal);
/**
* @brief Decode a particular channel's interrupt
*
* - Reads and clears the interrupt register of the channel
* - Returns the corresponding event for that channel
*
* @param chan_obj Channel object
* @return usbh_hal_chan_event_t Channel event
*/
usbh_hal_chan_event_t usbh_hal_chan_decode_intr(usbh_hal_chan_t *chan_obj);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,938 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/usbh_struct.h"
#include "soc/usb_wrap_struct.h"
#include "hal/usb_types.h"
/* -----------------------------------------------------------------------------
------------------------------- Global Registers -------------------------------
----------------------------------------------------------------------------- */
/*
* Interrupt bit masks of the GINTSTS and GINTMSK registers
*/
#define USB_LL_INTR_CORE_WKUPINT (1 << 31)
#define USB_LL_INTR_CORE_SESSREQINT (1 << 30)
#define USB_LL_INTR_CORE_DISCONNINT (1 << 29)
#define USB_LL_INTR_CORE_CONIDSTSCHNG (1 << 28)
#define USB_LL_INTR_CORE_PTXFEMP (1 << 26)
#define USB_LL_INTR_CORE_HCHINT (1 << 25)
#define USB_LL_INTR_CORE_PRTINT (1 << 24)
#define USB_LL_INTR_CORE_RESETDET (1 << 23)
#define USB_LL_INTR_CORE_FETSUSP (1 << 22)
#define USB_LL_INTR_CORE_INCOMPIP (1 << 21)
#define USB_LL_INTR_CORE_INCOMPISOIN (1 << 20)
#define USB_LL_INTR_CORE_OEPINT (1 << 19)
#define USB_LL_INTR_CORE_IEPINT (1 << 18)
#define USB_LL_INTR_CORE_EPMIS (1 << 17)
#define USB_LL_INTR_CORE_EOPF (1 << 15)
#define USB_LL_INTR_CORE_ISOOUTDROP (1 << 14)
#define USB_LL_INTR_CORE_ENUMDONE (1 << 13)
#define USB_LL_INTR_CORE_USBRST (1 << 12)
#define USB_LL_INTR_CORE_USBSUSP (1 << 11)
#define USB_LL_INTR_CORE_ERLYSUSP (1 << 10)
#define USB_LL_INTR_CORE_GOUTNAKEFF (1 << 7)
#define USB_LL_INTR_CORE_GINNAKEFF (1 << 6)
#define USB_LL_INTR_CORE_NPTXFEMP (1 << 5)
#define USB_LL_INTR_CORE_RXFLVL (1 << 4)
#define USB_LL_INTR_CORE_SOF (1 << 3)
#define USB_LL_INTR_CORE_OTGINT (1 << 2)
#define USB_LL_INTR_CORE_MODEMIS (1 << 1)
#define USB_LL_INTR_CORE_CURMOD (1 << 0)
/*
* Bit mask of interrupt generating bits of the the HPRT register. These bits
* are ORd into the USB_LL_INTR_CORE_PRTINT interrupt.
*
* Note: Some fields of the HPRT are W1C (write 1 clear), this we cannot do a
* simple read and write-back to clear the HPRT interrupt bits. Instead we need
* a W1C mask the non-interrupt related bits
*/
#define USBH_LL_HPRT_W1C_MSK (0x2E)
#define USBH_LL_HPRT_ENA_MSK (0x04)
#define USBH_LL_INTR_HPRT_PRTOVRCURRCHNG (1 << 5)
#define USBH_LL_INTR_HPRT_PRTENCHNG (1 << 3)
#define USBH_LL_INTR_HPRT_PRTCONNDET (1 << 1)
/*
* Bit mask of channel interrupts (HCINTi and HCINTMSKi registers)
*
* Note: Under Scatter/Gather DMA mode, only the following interrupts can be unmasked
* - DESC_LS_ROLL
* - XCS_XACT_ERR (always unmasked)
* - BNAINTR
* - CHHLTD
* - XFERCOMPL
* The remaining interrupt bits will still be set (when the corresponding event occurs)
* but will not generate an interrupt. Therefore we must proxy through the
* USBH_LL_INTR_CHAN_CHHLTD interrupt to check the other interrupt bits.
*/
#define USBH_LL_INTR_CHAN_DESC_LS_ROLL (1 << 13)
#define USBH_LL_INTR_CHAN_XCS_XACT_ERR (1 << 12)
#define USBH_LL_INTR_CHAN_BNAINTR (1 << 11)
#define USBH_LL_INTR_CHAN_DATATGLERR (1 << 10)
#define USBH_LL_INTR_CHAN_FRMOVRUN (1 << 9)
#define USBH_LL_INTR_CHAN_BBLEER (1 << 8)
#define USBH_LL_INTR_CHAN_XACTERR (1 << 7)
#define USBH_LL_INTR_CHAN_NYET (1 << 6)
#define USBH_LL_INTR_CHAN_ACK (1 << 5)
#define USBH_LL_INTR_CHAN_NAK (1 << 4)
#define USBH_LL_INTR_CHAN_STALL (1 << 3)
#define USBH_LL_INTR_CHAN_AHBERR (1 << 2)
#define USBH_LL_INTR_CHAN_CHHLTD (1 << 1)
#define USBH_LL_INTR_CHAN_XFERCOMPL (1 << 0)
/*
* QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode.
* Each QTD describes one transfer. Scatter gather mode will automatically split
* a transfer into multiple MPS packets. Each QTD is 64bits in size
*
* Note: The status information part of the QTD is interpreted differently depending
* on IN or OUT, and ISO or non-ISO
*/
typedef struct {
union {
struct {
uint32_t xfer_size: 17;
uint32_t aqtd_offset: 6;
uint32_t aqtd_valid: 1;
uint32_t reserved_24: 1;
uint32_t intr_cplt: 1;
uint32_t eol: 1;
uint32_t reserved_27: 1;
uint32_t rx_status: 2;
uint32_t reserved_30: 1;
uint32_t active: 1;
} in_non_iso;
struct {
uint32_t xfer_size: 12;
uint32_t reserved_12_24: 13;
uint32_t intr_cplt: 1;
uint32_t reserved_26_27: 2;
uint32_t rx_status: 2;
uint32_t reserved_30: 1;
uint32_t active: 1;
} in_iso;
struct {
uint32_t xfer_size: 17;
uint32_t reserved_17_23: 7;
uint32_t is_setup: 1;
uint32_t intr_cplt: 1;
uint32_t eol: 1;
uint32_t reserved_27: 1;
uint32_t tx_status: 2;
uint32_t reserved_30: 1;
uint32_t active: 1;
} out_non_iso;
struct {
uint32_t xfer_size: 12;
uint32_t reserved_12_24: 13;
uint32_t intr_cplt: 1;
uint32_t eol: 1;
uint32_t reserved_27: 1;
uint32_t tx_status: 2;
uint32_t reserved_30: 1;
uint32_t active: 1;
} out_iso;
uint32_t buffer_status_val;
};
uint8_t *buffer;
} usbh_ll_dma_qtd_t;
/*
* Enumeration of different possible lengths of the periodic frame list
*/
typedef enum {
USBH_LL_FRAME_LIST_LEN_8 = 0,
USBH_LL_FRAME_LIST_LEN_16,
USBH_LL_FRAME_LIST_LEN_32,
USBH_LL_FRAME_LIST_LEN_64,
} usbh_ll_frame_list_len_t;
/* -----------------------------------------------------------------------------
------------------------------ USB Wrap Registers ------------------------------
----------------------------------------------------------------------------- */
/**
* @brief Configures the internal PHY to operate as HOST
*
* @param hw Start address of the USB Wrap registers
*/
static inline void usbh_ll_internal_phy_conf(usb_wrap_dev_t *hw)
{
//Enable internal PHY
hw->otg_conf.pad_enable = 1;
hw->otg_conf.phy_sel = 0;
//Set pulldowns on D+ and D-
hw->otg_conf.pad_pull_override = 1;
hw->otg_conf.dp_pulldown = 1;
hw->otg_conf.dm_pulldown = 1;
}
/* -----------------------------------------------------------------------------
------------------------------- Global Registers -------------------------------
----------------------------------------------------------------------------- */
// --------------------------- GAHBCFG Register --------------------------------
static inline void usb_ll_en_dma_mode(usbh_dev_t *hw)
{
hw->gahbcfg_reg.dmaen = 1;
}
static inline void usb_ll_en_slave_mode(usbh_dev_t *hw)
{
hw->gahbcfg_reg.dmaen = 0;
}
static inline void usb_ll_set_hbstlen(usbh_dev_t *hw, uint32_t burst_len)
{
hw->gahbcfg_reg.hbstlen = burst_len;
}
static inline void usb_ll_en_global_intr(usbh_dev_t *hw)
{
hw->gahbcfg_reg.glbllntrmsk = 1;
}
static inline void usb_ll_dis_global_intr(usbh_dev_t *hw)
{
hw->gahbcfg_reg.glbllntrmsk = 0;
}
// --------------------------- GUSBCFG Register --------------------------------
static inline void usb_ll_set_host_mode(usbh_dev_t *hw)
{
hw->gusbcfg_reg.forcehstmode = 1;
}
static inline void usb_ll_dis_hnp_cap(usbh_dev_t *hw)
{
hw->gusbcfg_reg.hnpcap = 0;
}
static inline void usb_ll_dis_srp_cap(usbh_dev_t *hw)
{
hw->gusbcfg_reg.srpcap = 0;
}
// --------------------------- GRSTCTL Register --------------------------------
static inline bool usb_ll_check_ahb_idle(usbh_dev_t *hw)
{
return hw->grstctl_reg.ahbidle;
}
static inline bool usb_ll_check_dma_req_in_progress(usbh_dev_t *hw)
{
return hw->grstctl_reg.dmareq;
}
static inline void usb_ll_flush_tx_fifo(usbh_dev_t *hw, uint32_t chan_num)
{
usb_grstctl_reg_t grstctl;
grstctl.val = hw->grstctl_reg.val;
grstctl.txfnum = chan_num; //Set channel number to flush
grstctl.txfflsh = 1; //Flush that channel's TX FIFO
hw->grstctl_reg.val = grstctl.val;
}
static inline void usb_ll_flush_rx_fifo(usbh_dev_t *hw)
{
hw->grstctl_reg.rxfflsh = 1;
}
static inline void usb_ll_reset_frame_counter(usbh_dev_t *hw)
{
hw->grstctl_reg.frmcntrrst = 1;
}
static inline void usb_ll_core_soft_reset(usbh_dev_t *hw)
{
hw->grstctl_reg.csftrst = 1;
}
static inline bool usb_ll_check_core_soft_reset(usbh_dev_t *hw)
{
return hw->grstctl_reg.csftrst;
}
// --------------------------- GINTSTS Register --------------------------------
/**
* @brief Reads and clears the global interrupt register
*
* @param hw Start address of the DWC_OTG registers
* @return uint32_t Mask of interrupts
*/
static inline uint32_t usb_ll_intr_read_and_clear(usbh_dev_t *hw)
{
usb_gintsts_reg_t gintsts;
gintsts.val = hw->gintsts_reg.val;
hw->gintsts_reg.val = gintsts.val; //Write back to clear
return gintsts.val;
}
/**
* @brief Clear specific interrupts
*
* @param hw Start address of the DWC_OTG registers
* @param intr_msk Mask of interrupts to clear
*/
static inline void usb_ll_intr_clear(usbh_dev_t *hw, uint32_t intr_msk)
{
//All GINTSTS fields are either W1C or read only. So safe to write directly
hw->gintsts_reg.val = intr_msk;
}
// --------------------------- GINTMSK Register --------------------------------
static inline void usb_ll_en_intrs(usbh_dev_t *hw, uint32_t intr_mask)
{
hw->gintmsk_reg.val |= intr_mask;
}
static inline void usb_ll_dis_intrs(usbh_dev_t *hw, uint32_t intr_mask)
{
hw->gintmsk_reg.val &= ~intr_mask;
}
// --------------------------- GRXFSIZ Register --------------------------------
static inline void usb_ll_set_rx_fifo_size(usbh_dev_t *hw, uint32_t size)
{
//Set size in words
hw->grxfsiz_reg.rxfdep = size;
}
// -------------------------- GNPTXFSIZ Register -------------------------------
static inline void usb_ll_set_nptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t size)
{
usb_gnptxfsiz_reg_t gnptxfsiz;
gnptxfsiz.val = hw->gnptxfsiz_reg.val;
gnptxfsiz.nptxfstaddr = addr;
gnptxfsiz.nptxfdep = size;
hw->gnptxfsiz_reg.val = gnptxfsiz.val;
}
static inline uint32_t usb_ll_get_controller_core_id(usbh_dev_t *hw)
{
return hw->gsnpsid_reg.val;
}
/**
* @brief Get the hardware configuration regiters of the DWC_OTG controller
*
* The hardware configuraiton regitsers are read only and indicate the various
* features of the DWC_OTG core.
*
* @param hw Start address of the DWC_OTG registers
* @param[out] ghwcfg1 Hardware configuration registesr 1
* @param[out] ghwcfg2 Hardware configuration registesr 2
* @param[out] ghwcfg3 Hardware configuration registesr 3
* @param[out] ghwcfg4 Hardware configuration registesr 4
*/
static inline void usb_ll_get_hardware_config(usbh_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
{
*ghwcfg1 = hw->ghwcfg1_reg.val;
*ghwcfg2 = hw->ghwcfg2_reg.val;
*ghwcfg3 = hw->ghwcfg3_reg.val;
*ghwcfg4 = hw->ghwcfg4_reg.val;
}
// --------------------------- HPTXFSIZ Register -------------------------------
static inline void usbh_ll_set_ptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t size)
{
usb_hptxfsiz_reg_t hptxfsiz;
hptxfsiz.val = hw->hptxfsiz_reg.val;
hptxfsiz.ptxfstaddr = addr;
hptxfsiz.ptxfsize = size;
hw->hptxfsiz_reg.val = hptxfsiz.val;
}
/* -----------------------------------------------------------------------------
-------------------------------- Host Registers --------------------------------
----------------------------------------------------------------------------- */
// ----------------------------- HCFG Register ---------------------------------
static inline void usbh_ll_hcfg_en_perio_sched(usbh_dev_t *hw)
{
hw->hcfg_reg.perschedena = 1;
}
static inline void usbh_ll_hcfg_dis_perio_sched(usbh_dev_t *hw)
{
hw->hcfg_reg.perschedena = 0;
}
/**
* Sets the length of the frame list
*
* @param num_entires Number of entires in the frame list
*/
static inline void usbh_ll_hcfg_set_num_frame_list_entries(usbh_dev_t *hw, usbh_ll_frame_list_len_t num_entries)
{
hw->hcfg_reg.frlisten = num_entries;
}
static inline void usbh_ll_hcfg_en_scatt_gatt_dma(usbh_dev_t *hw)
{
hw->hcfg_reg.descdma = 1;
}
static inline void usbh_ll_hcfg_set_fsls_supp_only(usbh_dev_t *hw)
{
hw->hcfg_reg.fslssupp = 1;
}
static inline void usbh_ll_hcfg_set_fsls_pclk_sel(usbh_dev_t *hw)
{
hw->hcfg_reg.fslspclksel = 1;
}
/**
* @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA
*
* @param hw
*/
static inline void usbh_ll_hcfg_set_defaults(usbh_dev_t *hw, usb_speed_t speed)
{
hw->hcfg_reg.descdma = 1; //Enable scatt/gatt
hw->hcfg_reg.fslssupp = 1; //FS/LS supp only
/*
Indicate to the OTG core what speed the PHY clock is at
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/
hw->hcfg_reg.fslspclksel = (speed == USB_SPEED_FULL) ? 1 : 2;
hw->hcfg_reg.perschedena = 0; //Disable perio sched
}
// ----------------------------- HFIR Register ---------------------------------
static inline void usbh_ll_hfir_set_defaults(usbh_dev_t *hw, usb_speed_t speed)
{
usb_hfir_reg_t hfir;
hfir.val = hw->hfir_reg.val;
hfir.hfirrldctrl = 0; //Disable dynamic loading
/*
Set frame interval to be equal to 1ms
Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
*/
hfir.frint = (speed == USB_SPEED_FULL) ? 48000 : 6000;
hw->hfir_reg.val = hfir.val;
}
// ----------------------------- HFNUM Register --------------------------------
static inline uint32_t usbh_ll_get_frm_time_rem(usbh_dev_t *hw)
{
return hw->hfnum_reg.frrem;
}
static inline uint32_t usbh_ll_get_frm_num(usbh_dev_t *hw)
{
return hw->hfnum_reg.frnum;
}
// ---------------------------- HPTXSTS Register -------------------------------
static inline uint32_t usbh_ll_get_p_tx_queue_top(usbh_dev_t *hw)
{
return hw->hptxsts_reg.ptxqtop;
}
static inline uint32_t usbh_ll_get_p_tx_queue_space_avail(usbh_dev_t *hw)
{
return hw->hptxsts_reg.ptxqspcavail;
}
static inline uint32_t usbh_ll_get_p_tx_fifo_space_avail(usbh_dev_t *hw)
{
return hw->hptxsts_reg.ptxfspcavail;
}
// ----------------------------- HAINT Register --------------------------------
static inline uint32_t usbh_ll_get_chan_intrs_msk(usbh_dev_t *hw)
{
return hw->haint_reg.haint;
}
// --------------------------- HAINTMSK Register -------------------------------
static inline void usbh_ll_haintmsk_en_chan_intr(usbh_dev_t *hw, uint32_t mask)
{
hw->haintmsk_reg.val |= mask;
}
static inline void usbh_ll_haintmsk_dis_chan_intr(usbh_dev_t *hw, uint32_t mask)
{
hw->haintmsk_reg.val &= ~mask;
}
// --------------------------- HFLBAddr Register -------------------------------
static inline void usbh_ll_set_frame_list_base_addr(usbh_dev_t *hw, uint32_t addr)
{
hw->hflbaddr_reg.hflbaddr = addr;
}
static inline uint32_t usbh_ll_get_frame_list_base_addr(usbh_dev_t *hw)
{
return hw->hflbaddr_reg.hflbaddr;
}
// ----------------------------- HPRT Register ---------------------------------
static inline usb_speed_t usbh_ll_hprt_get_speed(usbh_dev_t *hw)
{
int prtspd = hw->hprt_reg.prtspd;
if (prtspd == 1) {
return USB_SPEED_FULL;
} else {
return USB_SPEED_LOW;
}
}
static inline uint32_t usbh_ll_hprt_get_test_ctl(usbh_dev_t *hw)
{
return hw->hprt_reg.prttstctl;
}
static inline void usbh_ll_hprt_set_test_ctl(usbh_dev_t *hw, uint32_t test_mode)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prttstctl = test_mode;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline void usbh_ll_hprt_en_pwr(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtpwr = 1;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline void usbh_ll_hprt_dis_pwr(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtpwr = 0;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline uint32_t usbh_ll_hprt_get_pwr_line_status(usbh_dev_t *hw)
{
return hw->hprt_reg.prtlnsts;
}
static inline void usbh_ll_hprt_set_port_reset(usbh_dev_t *hw, bool reset)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtrst = reset;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline bool usbh_ll_hprt_get_port_reset(usbh_dev_t *hw)
{
return hw->hprt_reg.prtrst;
}
static inline void usbh_ll_hprt_set_port_suspend(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtsusp = 1;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline bool usbh_ll_hprt_get_port_suspend(usbh_dev_t *hw)
{
return hw->hprt_reg.prtsusp;
}
static inline void usbh_ll_hprt_set_port_resume(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtres = 1;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline void usbh_ll_hprt_clr_port_resume(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtres = 0;
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
}
static inline bool usbh_ll_hprt_get_port_resume(usbh_dev_t *hw)
{
return hw->hprt_reg.prtres;
}
static inline bool usbh_ll_hprt_get_port_overcur(usbh_dev_t *hw)
{
return hw->hprt_reg.prtovrcurract;
}
static inline bool usbh_ll_hprt_get_port_en(usbh_dev_t *hw)
{
return hw->hprt_reg.prtena;
}
static inline void usbh_ll_hprt_port_dis(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hprt.prtena = 1; //W1C to disable
//we want to W1C ENA but not W1C the interrupt bits
hw->hprt_reg.val = hprt.val & ((~USBH_LL_HPRT_W1C_MSK) | USBH_LL_HPRT_ENA_MSK);
}
static inline bool usbh_ll_hprt_get_conn_status(usbh_dev_t *hw)
{
return hw->hprt_reg.prtconnsts;
}
static inline uint32_t usbh_ll_hprt_intr_read_and_clear(usbh_dev_t *hw)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
//We want to W1C the interrupt bits but not that ENA
hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_ENA_MSK);
//Return only the interrupt bits
return (hprt.val & (USBH_LL_HPRT_W1C_MSK & ~(USBH_LL_HPRT_ENA_MSK)));
}
static inline void usbh_ll_hprt_intr_clear(usbh_dev_t *hw, uint32_t intr_mask)
{
usb_hprt_reg_t hprt;
hprt.val = hw->hprt_reg.val;
hw->hprt_reg.val = ((hprt.val & ~USBH_LL_HPRT_ENA_MSK) & ~USBH_LL_HPRT_W1C_MSK) | intr_mask;
}
//Per Channel registers
// --------------------------- HCCHARi Register --------------------------------
static inline void usbh_ll_chan_start(volatile usb_host_chan_regs_t *chan)
{
chan->hcchar_reg.chena = 1;
}
static inline bool usbh_ll_chan_is_active(volatile usb_host_chan_regs_t *chan)
{
return chan->hcchar_reg.chena;
}
static inline void usbh_ll_chan_halt(volatile usb_host_chan_regs_t *chan)
{
chan->hcchar_reg.chdis = 1;
}
static inline void usbh_ll_chan_xfer_odd_frame(volatile usb_host_chan_regs_t *chan)
{
chan->hcchar_reg.oddfrm = 1;
}
static inline void usbh_ll_chan_xfer_even_frame(volatile usb_host_chan_regs_t *chan)
{
chan->hcchar_reg.oddfrm = 0;
}
static inline void usbh_ll_chan_set_dev_addr(volatile usb_host_chan_regs_t *chan, uint32_t addr)
{
chan->hcchar_reg.devaddr = addr;
}
static inline void usbh_ll_chan_set_ep_type(volatile usb_host_chan_regs_t *chan, usb_xfer_type_t type)
{
switch (type) {
case USB_XFER_TYPE_CTRL:
chan->hcchar_reg.eptype = 0x0;
break;
case USB_XFER_TYPE_ISOCHRONOUS:
chan->hcchar_reg.eptype = 0x1;
break;
case USB_XFER_TYPE_BULK:
chan->hcchar_reg.eptype = 0x2;
break;
case USB_XFER_TYPE_INTR:
chan->hcchar_reg.eptype = 0x3;
break;
default:
;
}
}
//Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause
//each packet to be preceded by a PREamble packet
static inline void usbh_ll_chan_set_lspddev(volatile usb_host_chan_regs_t *chan, bool is_ls)
{
chan->hcchar_reg.lspddev = is_ls;
}
static inline void usbh_ll_chan_set_dir(volatile usb_host_chan_regs_t *chan, bool is_in)
{
chan->hcchar_reg.epdir = is_in;
}
static inline void usbh_ll_chan_set_ep_num(volatile usb_host_chan_regs_t *chan, uint32_t num)
{
chan->hcchar_reg.epnum = num;
}
static inline void usbh_ll_chan_set_mps(volatile usb_host_chan_regs_t *chan, uint32_t mps)
{
chan->hcchar_reg.mps = mps;
}
static inline void usbh_ll_chan_hcchar_init(volatile usb_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_xfer_type_t type, bool is_in, bool is_ls)
{
//Sets all persistent fields of the channel over its lifetime
usbh_ll_chan_set_dev_addr(chan, dev_addr);
usbh_ll_chan_set_ep_type(chan, type);
usbh_ll_chan_set_lspddev(chan, is_ls);
usbh_ll_chan_set_dir(chan, is_in);
usbh_ll_chan_set_ep_num(chan, ep_num);
usbh_ll_chan_set_mps(chan, mps);
}
// ---------------------------- HCINTi Register --------------------------------
static inline uint32_t usbh_ll_chan_intr_read_and_clear(volatile usb_host_chan_regs_t *chan)
{
usb_hcint_reg_t hcint;
hcint.val = chan->hcint_reg.val;
chan->hcint_reg.val = hcint.val;
return hcint.val;
}
// --------------------------- HCINTMSKi Register ------------------------------
static inline void usbh_ll_chan_set_intr_mask(volatile usb_host_chan_regs_t *chan, uint32_t mask)
{
chan->hcintmsk_reg.val = mask;
}
// ---------------------- HCTSIZi and HCDMAi Registers -------------------------
static inline void usbh_ll_chan_set_pid(volatile usb_host_chan_regs_t *chan, uint32_t data_pid)
{
if (data_pid == 0) {
chan->hctsiz_reg.pid = 0;
} else {
chan->hctsiz_reg.pid = 2;
}
}
static inline uint32_t usbh_ll_chan_get_pid(volatile usb_host_chan_regs_t *chan) {
if (chan->hctsiz_reg.pid == 0) {
return 0; //DATA0
} else {
return 1; //DATA1
}
}
static inline void usbh_ll_chan_set_dma_addr_non_iso(volatile usb_host_chan_regs_t *chan,
void *dmaaddr,
uint32_t qtd_idx)
{
//Set HCDMAi
chan->hcdma_reg.val = 0;
chan->hcdma_reg.non_iso.dmaaddr = (((uint32_t)dmaaddr) >> 9) & 0x7FFFFF; //MSB of 512 byte aligned address
chan->hcdma_reg.non_iso.ctd = qtd_idx;
}
static inline void usbh_ll_chan_set_dma_addr_iso(volatile usb_host_chan_regs_t *chan,
void *dmaaddr,
uint32_t ntd,
uint32_t pktcnt,
uint32_t ctd)
{
int n;
if (ntd == 2) {
n = 4;
} else if (ntd == 4) {
n = 5;
} else if (ntd == 8) {
n = 6;
} else if (ntd == 16) {
n = 7;
} else if (ntd == 32) {
n = 8;
} else { //ntd == 64
n = 9;
}
//Set HCTSIZi
chan->hctsiz_reg.ntd = ntd -1;
chan->hctsiz_reg.sched_info = 0xFF; //Always set to 0xFF for FS
//Set HCDMAi
chan->hcdma_reg.iso.dmaaddr_ctd = (((uint32_t)dmaaddr) & 0x1FF) << (n-3); //ctd is set to 0
}
static inline int usbh_ll_chan_get_ctd(usb_host_chan_regs_t *chan)
{
return chan->hcdma_reg.non_iso.ctd;
}
static inline void usbh_ll_chan_hctsiz_init(volatile usb_host_chan_regs_t *chan)
{
chan->hctsiz_reg.dopng = 0; //Don't do ping
chan->hctsiz_reg.sched_info = 0xFF; //Schedinfo is always 0xFF for fullspeed. Not used in Bulk/Ctrl channels
}
static inline void usbh_ll_chan_set_qtd_list_len(volatile usb_host_chan_regs_t *chan, int qtd_list_len)
{
chan->hctsiz_reg.ntd = qtd_list_len - 1; //Set the length of the descriptor list
}
// ---------------------------- HCDMABi Register -------------------------------
static inline void *usbh_ll_chan_get_cur_buff_addr(volatile usb_host_chan_regs_t *chan)
{
return (void *)chan->hcdmab_reg.hcdmab;
}
/* -----------------------------------------------------------------------------
---------------------------- Scatter/Gather DMA QTDs ---------------------------
----------------------------------------------------------------------------- */
// ---------------------------- Helper Functions -------------------------------
/**
* @brief Get the base address of a channel's register based on the channel's index
*
* @param dev Start address of the DWC_OTG registers
* @param chan_idx The channel's index
* @return usb_host_chan_regs_t* Pointer to channel's registers
*/
static inline usb_host_chan_regs_t *usbh_ll_get_chan_regs(usbh_dev_t *dev, int chan_idx)
{
return &dev->host_chans[chan_idx];
}
// ------------------------------ QTD related ----------------------------------
#define USBH_LL_QTD_STATUS_SUCCESS 0x0 //If QTD was processed, it indicates the data was transmitted/received successfully
#define USBH_LL_QTD_STATUS_PKTERR 0x1 //Data trasnmitted/received with errors (CRC/Timeout/Stuff/False EOP/Excessive NAK).
//Note: 0x2 is reserved
#define USBH_LL_QTD_STATUS_BUFFER 0x3 //AHB error occurred.
#define USBH_LL_QTD_STATUS_NOT_EXECUTED 0x4 //QTD as never processed
/**
* @brief Set a QTD for a non isochronous IN transfer
*
* @param qtd Pointer to the QTD
* @param data_buff Pointer to buffer containing the data to transfer
* @param xfer_len Number of bytes in transfer. Setting 0 will do a zero length IN transfer.
* Non zero length must be mulitple of the endpoint's MPS.
* @param halt_on_cplt Generate a channel halted interrupt on completion of QTD
*/
static inline void usbh_ll_set_qtd_in(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool halt_on_cplt)
{
qtd->buffer = data_buff; //Set pointer to data buffer
qtd->buffer_status_val = 0; //Reset all flags to zero
qtd->in_non_iso.xfer_size = xfer_len;
if (halt_on_cplt) {
qtd->in_non_iso.intr_cplt = 1; //Used to indicate successful completion
qtd->in_non_iso.eol = 1; //Used to halt the channel at this qtd
}
qtd->in_non_iso.active = 1;
}
/**
* @brief Set a QTD for a non isochronous OUT transfer
*
* @param qtd Poitner to the QTD
* @param data_buff Pointer to buffer containing the data to transfer
* @param xfer_len Number of bytes to transfer. Setting 0 will do a zero length transfer.
* For ctrl setup packets, this should be set to 8.
* @param halt_on_cplt Generate a channel halted interrupt on completion of QTD.
* @param is_setup Indicates whether this is a control transfer setup packet or a normal OUT Data transfer.
* (As per the USB protocol, setup packets cannot be STALLd or NAKd by the device)
*/
static inline void usbh_ll_set_qtd_out(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool halt_on_cplt, bool is_setup)
{
qtd->buffer = data_buff; //Set pointer to data buffer
qtd->buffer_status_val = 0; //Reset all flags to zero
qtd->out_non_iso.xfer_size = xfer_len;
if (is_setup) {
qtd->out_non_iso.is_setup = 1;
}
if (halt_on_cplt) {
qtd->out_non_iso.intr_cplt = 1; //Used to indicate successful completion
qtd->out_non_iso.eol = 1; //Used to halt the channel at this qtd
}
qtd->out_non_iso.active = 1;
}
/**
* @brief Set a QTD as NULL
*
* This sets the QTD to a value of 0. This is only useful when you need to insert
* blank QTDs into a list of QTDs
*
* @param qtd Pointer to the QTD
*/
static inline void usbh_ll_set_qtd_null(usbh_ll_dma_qtd_t *qtd)
{
qtd->buffer = NULL;
qtd->buffer_status_val = 0; //Disable qtd by clearing it to zero. Used by interrupt/isoc as an unscheudled frame
}
/**
* @brief Get the status of a QTD
*
* When a channel get's halted, call this to check whether each QTD was executed successfully
*
* @param qtd Poitner to the QTD
* @param[out] rem_len Number of bytes ramining in the QTD
* @param[out] status Status of the QTD
*/
static inline void usbh_ll_get_qtd_status(usbh_ll_dma_qtd_t *qtd, int *rem_len, int *status)
{
//Status is the same regardless of IN or OUT
if (qtd->in_non_iso.active) {
//QTD was never processed
*status = USBH_LL_QTD_STATUS_NOT_EXECUTED;
} else {
*status = qtd->in_non_iso.rx_status;
}
*rem_len = qtd->in_non_iso.xfer_size;
//Clear the QTD just for safety
qtd->buffer_status_val = 0;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,383 @@
#pragma once
#include "soc/soc_caps.h"
#include "hal/adc_types.h"
#include "hal/adc_ll.h"
#include "esp_err.h"
#if CONFIG_IDF_TARGET_ESP32C3
#include "soc/gdma_struct.h"
#include "hal/gdma_ll.h"
#include "hal/dma_types.h"
#include "hal/adc_ll.h"
#include "hal/dma_types.h"
#include "esp_err.h"
//For ADC module, each conversion contains 4 bytes
#define ADC_HAL_DATA_LEN_PER_CONV 4
/**
* @brief Enum for DMA descriptor status
*/
typedef enum adc_hal_dma_desc_status_t {
ADC_HAL_DMA_DESC_VALID = 0, ///< This DMA descriptor is written by HW already
ADC_HAL_DMA_DESC_WAITING = 1, ///< This DMA descriptor is not written by HW yet
ADC_HAL_DMA_DESC_NULL = 2 ///< This DMA descriptor is NULL
} adc_hal_dma_desc_status_t;
/**
* @brief Configuration of the HAL
*/
typedef struct adc_hal_config_t {
uint32_t desc_max_num; ///< Number of the descriptors linked once
uint32_t dma_chan; ///< DMA channel to be used
uint32_t eof_num; ///< Bytes between 2 in_suc_eof interrupts
} adc_hal_config_t;
/**
* @brief Context of the HAL
*/
typedef struct adc_hal_context_t {
/**< this needs to be malloced by the driver layer first */
dma_descriptor_t *rx_desc; ///< DMA descriptors
/**< these will be assigned by hal layer itself */
gdma_dev_t *dev; ///< GDMA address
dma_descriptor_t desc_dummy_head; ///< Dummy DMA descriptor for ``cur_desc_ptr`` to start
dma_descriptor_t *cur_desc_ptr; ///< Pointer to the current descriptor
/**< these need to be configured by `adc_hal_config_t` via driver layer*/
uint32_t desc_max_num; ///< Number of the descriptors linked once
uint32_t dma_chan; ///< DMA channel to be used
uint32_t eof_num; ///< Words between 2 in_suc_eof interrupts
} adc_hal_context_t;
#endif
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* ADC module initialization.
*/
void adc_hal_init(void);
/**
* Set ADC module power management.
*
* @prarm manage Set ADC power status.
*/
#define adc_hal_set_power_manage(manage) adc_ll_set_power_manage(manage)
/**
* ADC module clock division factor setting. ADC clock devided from APB clock.
*
* @prarm div Division factor.
*/
#define adc_hal_digi_set_clk_div(div) adc_ll_digi_set_clk_div(div)
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* ADC SAR clock division factor setting. ADC SAR clock devided from `RTC_FAST_CLK`.
*
* @prarm div Division factor.
*/
#define adc_hal_set_sar_clk_div(adc_n, div) adc_ll_set_sar_clk_div(adc_n, div)
/**
* Set ADC module controller.
* There are five SAR ADC controllers:
* Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes;
* Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep;
* the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2.
*
* @prarm adc_n ADC unit.
* @prarm ctrl ADC controller.
*/
#define adc_hal_set_controller(adc_n, ctrl) adc_ll_set_controller(adc_n, ctrl)
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/**
* Get the attenuation of a particular channel on ADCn.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @return atten The attenuation option.
*/
#define adc_hal_get_atten(adc_n, channel) adc_ll_get_atten(adc_n, channel)
#endif
#if CONFIG_IDF_TARGET_ESP32
/**
* Close ADC AMP module if don't use it for power save.
*/
#define adc_hal_amp_disable() adc_ll_amp_disable()
#endif
/*---------------------------------------------------------------
PWDET(Power detect) controller setting
---------------------------------------------------------------*/
/**
* Set adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @prarm cct Range: 0 ~ 7.
*/
#define adc_hal_pwdet_set_cct(cct) adc_ll_pwdet_set_cct(cct)
/**
* Get adc cct for PWDET controller.
*
* @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY.
* @return cct Range: 0 ~ 7.
*/
#define adc_hal_pwdet_get_cct() adc_ll_pwdet_get_cct()
/*---------------------------------------------------------------
RTC controller setting
---------------------------------------------------------------*/
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* Set adc output data format for RTC controller.
*
* @prarm adc_n ADC unit.
* @prarm bits Output data bits width option.
*/
#define adc_hal_rtc_set_output_format(adc_n, bits) adc_ll_rtc_set_output_format(adc_n, bits)
/**
* ADC module output data invert or not.
*
* @prarm adc_n ADC unit.
*/
#define adc_hal_rtc_output_invert(adc_n, inv_en) adc_ll_rtc_output_invert(adc_n, inv_en)
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
/**
* Enable/disable the output of ADCn's internal reference voltage to one of ADC2's channels.
*
* This function routes the internal reference voltage of ADCn to one of
* ADC2's channels. This reference voltage can then be manually measured
* for calibration purposes.
*
* @note ESP32 only supports output of ADC2's internal reference voltage.
* @param[in] adc ADC unit select
* @param[in] channel ADC2 channel number
* @param[in] en Enable/disable the reference voltage output
*/
#define adc_hal_vref_output(adc, channel, en) adc_ll_vref_output(adc, channel, en)
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
/**
* Digital controller deinitialization.
*/
void adc_hal_digi_deinit(void);
/**
* Setting the digital controller.
*
* @param cfg Pointer to digital controller paramter.
*/
void adc_hal_digi_controller_config(const adc_digi_config_t *cfg);
/**
* Reset the pattern table pointer, then take the measurement rule from table header in next measurement.
*
* @param adc_n ADC unit.
*/
#define adc_hal_digi_clear_pattern_table(adc_n) adc_ll_digi_clear_pattern_table(adc_n)
/*---------------------------------------------------------------
ADC Single Read
---------------------------------------------------------------*/
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* Set the attenuation of a particular channel on ADCn.
*
* @note For any given channel, this function must be called before the first time conversion.
*
* The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage,
* usually 3.3V) requires setting >0dB signal attenuation for that ADC channel.
*
* When VDD_A is 3.3V:
*
* - 0dB attenuaton (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V
* - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V
* - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V
* - 11dB attenuation (ADC_ATTEN_DB_11) gives full-scale voltage 3.9V (see note below)
*
* @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured
* bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.)
*
* @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage.
*
* Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges:
*
* - 0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV
* - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV
* - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV
* - 11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @param adc_n ADC unit.
* @param channel ADCn channel number.
* @param atten ADC attenuation. See ``adc_atten_t``
*/
#define adc_hal_set_atten(adc_n, channel, atten) adc_ll_set_atten(adc_n, channel, atten)
#else // CONFIG_IDF_TARGET_ESP32C3
/**
* Set the attenuation for ADC to single read
*
* @note All ADC units and channels will share the setting. So PLEASE DO save your attenuations and reset them by calling this API again in your driver
*
* @param adc_n Not used, leave here for chip version compatibility
* @param channel Not used, leave here for chip version compatibility
* @param atten ADC attenuation. See ``adc_atten_t``
*/
#define adc_hal_set_atten(adc_n, channel, atten) adc_ll_onetime_set_atten(atten)
#endif
/**
* Start an ADC conversion and get the converted value.
*
* @note It may be block to wait conversion finish.
*
* @param adc_n ADC unit.
* @param channel ADC channel number.
* @param[out] out_raw ADC converted result
*
* @return
* - ESP_OK: The value is valid.
* - ESP_ERR_INVALID_STATE: The value is invalid.
*/
esp_err_t adc_hal_convert(adc_ll_num_t adc_n, int channel, int *out_raw);
/*---------------------------------------------------------------
ADC calibration setting
---------------------------------------------------------------*/
#if SOC_ADC_HW_CALIBRATION_V1
// ESP32-S2 and C3 support HW offset calibration.
/**
* @brief Initialize default parameter for the calibration block.
*
* @param adc_n ADC index numer
*/
void adc_hal_calibration_init(adc_ll_num_t adc_n);
/**
* Set the calibration result (initial data) to ADC.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param param the calibration parameter to configure
*/
void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param);
/**
* Calibrate the ADC using internal connections.
*
* @note Different ADC units and different attenuation options use different calibration data (initial data).
*
* @param adc_n ADC index number.
* @param channel adc channel number.
* @param atten The attenuation for the channel
* @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage.
* false: Use IO external voltage as calibration voltage.
*
* @return
* - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set.
*/
uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd);
#endif //SOC_ADC_HW_CALIBRATION_V1
#if CONFIG_IDF_TARGET_ESP32C3
/*---------------------------------------------------------------
DMA setting
---------------------------------------------------------------*/
/**
* @brief Initialize the hal context
*
* @param hal Context of the HAL
* @param config Configuration of the HAL
*/
void adc_hal_context_config(adc_hal_context_t *hal, const adc_hal_config_t *config);
/**
* @brief Initialize the HW
*
* @param hal Context of the HAL
*/
void adc_hal_digi_init(adc_hal_context_t *hal);
/**
* @brief Reset ADC / DMA fifo
*
* @param hal Context of the HAL
*/
void adc_hal_fifo_reset(adc_hal_context_t *hal);
/**
* @brief Start DMA
*
* @param hal Context of the HAL
* @param data_buf Pointer to the data buffer, the length should be multiple of ``desc_max_num`` and ``eof_num`` in ``adc_hal_context_t``
*/
void adc_hal_digi_rxdma_start(adc_hal_context_t *hal, uint8_t *data_buf);
/**
* @brief Start ADC
*
* @param hal Context of the HAL
*/
void adc_hal_digi_start(adc_hal_context_t *hal);
/**
* @brief Get the ADC reading result
*
* @param hal Context of the HAL
* @param eof_desc_addr The last descriptor that is finished by HW. Should be got from DMA
* @param[out] cur_desc The descriptor with ADC reading result (from the 1st one to the last one (``eof_desc_addr``))
*
* @return See ``adc_hal_dma_desc_status_t``
*/
adc_hal_dma_desc_status_t adc_hal_get_reading_result(adc_hal_context_t *hal, const intptr_t eof_desc_addr, dma_descriptor_t **cur_desc);
/**
* @brief Stop DMA
*
* @param hal Context of the HAL
*/
void adc_hal_digi_rxdma_stop(adc_hal_context_t *hal);
/**
* @brief Clear interrupt
*
* @param hal Context of the HAL
* @param mask mask of the interrupt
*/
void adc_hal_digi_clr_intr(adc_hal_context_t *hal, uint32_t mask);
/**
* @brief Enable interrupt
*
* @param hal Context of the HAL
* @param mask mask of the interrupt
*/
void adc_hal_digi_dis_intr(adc_hal_context_t *hal, uint32_t mask);
/**
* @brief Stop ADC
*
* @param hal Context of the HAL
*/
void adc_hal_digi_stop(adc_hal_context_t *hal);
#endif //#if CONFIG_IDF_TARGET_ESP32C3

View File

@@ -0,0 +1,441 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_attr.h"
/**
* @brief ADC unit enumeration.
*
* @note For ADC digital controller (DMA mode), ESP32 doesn't support `ADC_UNIT_2`, `ADC_UNIT_BOTH`, `ADC_UNIT_ALTER`.
*/
typedef enum {
ADC_UNIT_1 = 1, /*!< SAR ADC 1. */
ADC_UNIT_2 = 2, /*!< SAR ADC 2. */
ADC_UNIT_BOTH = 3, /*!< SAR ADC 1 and 2. */
ADC_UNIT_ALTER = 7, /*!< SAR ADC 1 and 2 alternative mode. */
ADC_UNIT_MAX,
} adc_unit_t;
/**
* @brief ADC channels handle. See ``adc1_channel_t``, ``adc2_channel_t``.
*
* @note For ESP32 ADC1, don't use `ADC_CHANNEL_8`, `ADC_CHANNEL_9`. See ``adc1_channel_t``.
*/
typedef enum {
ADC_CHANNEL_0 = 0, /*!< ADC channel */
ADC_CHANNEL_1, /*!< ADC channel */
ADC_CHANNEL_2, /*!< ADC channel */
ADC_CHANNEL_3, /*!< ADC channel */
ADC_CHANNEL_4, /*!< ADC channel */
ADC_CHANNEL_5, /*!< ADC channel */
ADC_CHANNEL_6, /*!< ADC channel */
ADC_CHANNEL_7, /*!< ADC channel */
ADC_CHANNEL_8, /*!< ADC channel */
ADC_CHANNEL_9, /*!< ADC channel */
ADC_CHANNEL_MAX,
} adc_channel_t;
/**
* @brief ADC attenuation parameter. Different parameters determine the range of the ADC. See ``adc1_config_channel_atten``.
*/
typedef enum {
ADC_ATTEN_DB_0 = 0, /*!<No input attenumation, ADC can measure up to approx. 800 mV. */
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 1100 mV. */
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 1350 mV. */
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated, extending the range of measurement to up to approx. 2600 mV. */
ADC_ATTEN_MAX,
} adc_atten_t;
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* @brief ESP32 ADC DMA source selection.
*/
#else
/**
* @brief ESP32 ADC DMA source selection.
*
* @deprecated Not applicable on ESP32-S2 because ESP32-S2 doesn't use I2S DMA.
*/
#endif
typedef enum {
ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */
ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */
ADC_I2S_DATA_SRC_MAX,
} adc_i2s_source_t;
/**
* @brief ADC resolution setting option.
*
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32
ADC_WIDTH_BIT_9 = 0, /*!< ADC capture width is 9Bit. */
ADC_WIDTH_BIT_10 = 1, /*!< ADC capture width is 10Bit. */
ADC_WIDTH_BIT_11 = 2, /*!< ADC capture width is 11Bit. */
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_MAX_BITWIDTH == 12
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_MAX_BITWIDTH == 13
ADC_WIDTH_BIT_13 = 4, /*!< ADC capture width is 13Bit. */
#endif
ADC_WIDTH_MAX,
} adc_bits_width_t;
/**
* @brief ADC digital controller (DMA mode) work mode.
*
* @note The conversion mode affects the sampling frequency:
* SINGLE_UNIT_1: When the measurement is triggered, only ADC1 is sampled once.
* SINGLE_UNIT_2: When the measurement is triggered, only ADC2 is sampled once.
* BOTH_UNIT : When the measurement is triggered, ADC1 and ADC2 are sampled at the same time.
* ALTER_UNIT : When the measurement is triggered, ADC1 or ADC2 samples alternately.
*/
typedef enum {
ADC_CONV_SINGLE_UNIT_1 = 1, /*!< SAR ADC 1. */
ADC_CONV_SINGLE_UNIT_2 = 2, /*!< SAR ADC 2. */
ADC_CONV_BOTH_UNIT = 3, /*!< SAR ADC 1 and 2. */
ADC_CONV_ALTER_UNIT = 7, /*!< SAR ADC 1 and 2 alternative mode. */
ADC_CONV_UNIT_MAX,
} adc_digi_convert_mode_t;
/**
* @brief ADC digital controller (DMA mode) conversion rules setting.
*/
typedef struct {
union {
struct {
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
0: measurement range 0 - 800mV,
1: measurement range 0 - 1100mV,
2: measurement range 0 - 1350mV,
3: measurement range 0 - 2600mV. */
#if CONFIG_IDF_TARGET_ESP32
uint8_t bit_width: 2; /*!< ADC resolution.
- 0: 9 bit;
- 1: 10 bit;
- 2: 11 bit;
- 3: 12 bit. */
int8_t channel: 4; /*!< ADC channel index. */
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
uint8_t reserved: 2; /*!< reserved0 */
uint8_t channel: 4; /*!< ADC channel index. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint8_t channel: 3; /*!< ADC channel index. */
uint8_t unit: 1; /*!< ADC unit index. */
uint8_t reserved: 2; /*!< reserved0 */
#endif
};
uint8_t val; /*!<Raw data value */
};
} adc_digi_pattern_table_t;
/**
* @brief ADC digital controller (DMA mode) output data format option.
*/
typedef enum {
ADC_DIGI_FORMAT_12BIT, /*!<ADC to DMA data format, [15:12]-channel, [11: 0]-12 bits ADC data (`adc_digi_output_data_t`).
Note: For single convert mode. */
ADC_DIGI_FORMAT_11BIT, /*!<ADC to DMA data format, [15]-adc unit, [14:11]-channel, [10: 0]-11 bits ADC data (`adc_digi_output_data_t`).
Note: For multi or alter convert mode. */
ADC_DIGI_FORMAT_MAX,
} adc_digi_output_format_t;
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
*
* @note ESP32-S2:
* Member `channel` can be used to judge the validity of the ADC data, because the role of the arbiter may get invalid ADC data.
*/
typedef struct {
union {
struct {
uint16_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
uint16_t channel: 4; /*!<ADC channel index info. For ESP32-S2:
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
} type1; /*!<When the configured output format is 12bit. `ADC_DIGI_FORMAT_12BIT` */
struct {
uint16_t data: 11; /*!<ADC real output data info. Resolution: 11 bit. */
uint16_t channel: 4; /*!<ADC channel index info. For ESP32-S2:
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint16_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
} type2; /*!<When the configured output format is 11bit. `ADC_DIGI_FORMAT_11BIT` */
uint16_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#endif
#if CONFIG_IDF_TARGET_ESP32C3
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
*/
typedef struct {
union {
struct {
uint32_t data: 12; /*!<ADC real output data info. Resolution: 12 bit. */
uint32_t reserved12: 1; /*!<Reserved12. */
uint32_t channel: 3; /*!<ADC channel index info.
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint32_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
uint32_t reserved17_31: 15; /*!<Reserved17. */
} type2; /*!<When the configured output format is 12bit. `ADC_DIGI_FORMAT_11BIT` */
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#endif
#if !CONFIG_IDF_TARGET_ESP32
/**
* @brief ADC digital controller (DMA mode) clock system setting.
* Calculation formula: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
*
* @note: The clocks of the DAC digital controller use the ADC digital controller clock divider.
*/
typedef struct {
bool use_apll; /*!<true: use APLL clock; false: use APB clock. */
uint32_t div_num; /*!<Division factor. Range: 0 ~ 255.
Note: When a higher frequency clock is used (the division factor is less than 9),
the ADC reading value will be slightly offset. */
uint32_t div_b; /*!<Division factor. Range: 1 ~ 63. */
uint32_t div_a; /*!<Division factor. Range: 0 ~ 63. */
} adc_digi_clk_t;
#endif //!CONFIG_IDF_TARGET_ESP32
/**
* @brief ADC digital controller (DMA mode) configuration parameters.
*
* Example setting: When using ADC1 channel0 to measure voltage, the sampling rate is required to be 1 kHz:
*
* +---------------------+--------+--------+--------+
* | sample rate | 1 kHz | 1 kHz | 1 kHz |
* +---------------------+--------+--------+--------+
* | conv_mode | single | both | alter |
* | adc1_pattern_len | 1 | 1 | 1 |
* | dig_clk.use_apll | 0 | 0 | 0 |
* | dig_clk.div_num | 99 | 99 | 99 |
* | dig_clk.div_b | 0 | 0 | 0 |
* | dig_clk.div_a | 0 | 0 | 0 |
* | interval | 400 | 400 | 200 |
* +---------------------+--------+--------+--------+
* | `trigger_meas_freq` | 1 kHz | 1 kHz | 2 kHz |
* +---------------------+--------+--------+--------+
*
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
*
* +---------------------+--------+--------+--------+
* | conv_mode | single | both | alter |
* +---------------------+--------+--------+--------+
* | trigger meas times | 1 | 1 | 1 |
* +---------------------+--------+--------+--------+
* | conv_limit_num | +1 | +1 | +1 |
* | dma_eof_num | +1 | +2 | +1 |
* | dma output (byte) | +2 | +4 | +2 |
* +---------------------+--------+--------+--------+
*/
typedef struct {
bool conv_limit_en; /*!<Enable the function of limiting ADC conversion times.
If the number of ADC conversion trigger count is equal to the `limit_num`, the conversion is stopped. */
uint32_t conv_limit_num; /*!<Set the upper limit of the number of ADC conversion triggers. Range: 1 ~ 255. */
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
adc_digi_output_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_output_format_t``. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint32_t adc_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 7 (0: Don't change the pattern table setting).
The pattern table that defines the conversion rules for each SAR ADC. Each table has 7 items, in which channel selection,
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
adc_digi_pattern_table_t *adc_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc_pattern_len`. */
#endif
#if CONFIG_IDF_TARGET_ESP32S2
uint32_t interval; /*!<The number of interval clock cycles for the digital controller to trigger the measurement.
The unit is the divided clock. Range: 40 ~ 4095.
Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. Refer to ``adc_digi_clk_t``.
Note: The sampling rate of each channel is also related to the conversion mode (See ``adc_digi_convert_mode_t``) and pattern table settings. */
adc_digi_clk_t dig_clk; /*!<ADC digital controller clock divider settings. Refer to ``adc_digi_clk_t``.
Note: The clocks of the DAC digital controller use the ADC digital controller clock divider. */
uint32_t dma_eof_num; /*!<DMA eof num of adc digital controller.
If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated in DMA.
Note: The converted data in the DMA in link buffer will be multiple of two bytes. */
#elif CONFIG_IDF_TARGET_ESP32C3
uint32_t sample_freq_hz; /*!< The expected ADC sampling frequency in Hz. Range: 611Hz ~ 83333Hz
Fs = Fd / interval / 2
Fs: sampling frequency;
Fd: digital controller frequency, no larger than 5M for better performance
interval: interval between 2 measurement trigger signal, the smallest interval should not be smaller than the ADC measurement period, the largest interval should not be larger than 4095 */
#endif
} adc_digi_config_t;
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
/**
* @brief ADC digital controller (DMA mode) interrupt type options.
*/
typedef enum {
ADC_DIGI_INTR_MASK_MONITOR = 0x1,
ADC_DIGI_INTR_MASK_MEAS_DONE = 0x2,
ADC_DIGI_INTR_MASK_ALL = 0x3,
} adc_digi_intr_t;
FLAG_ATTR(adc_digi_intr_t)
#endif
#if !CONFIG_IDF_TARGET_ESP32
/**
* @brief ADC arbiter work mode option.
*
* @note ESP32-S2: Only ADC2 support arbiter.
*/
typedef enum {
ADC_ARB_MODE_SHIELD,/*!<Force shield arbiter, Select the highest priority controller to work. */
ADC_ARB_MODE_FIX, /*!<Fixed priority switch controller mode. */
ADC_ARB_MODE_LOOP, /*!<Loop priority switch controller mode. Each controller has the same priority,
and the arbiter will switch to the next controller after the measurement is completed. */
} adc_arbiter_mode_t;
/**
* @brief ADC arbiter work mode and priority setting.
*
* @note ESP32-S2: Only ADC2 support arbiter.
*/
typedef struct {
adc_arbiter_mode_t mode; /*!<Refer to ``adc_arbiter_mode_t``. Note: only support ADC2. */
uint8_t rtc_pri; /*!<RTC controller priority. Range: 0 ~ 2. */
uint8_t dig_pri; /*!<Digital controller priority. Range: 0 ~ 2. */
uint8_t pwdet_pri; /*!<Wi-Fi controller priority. Range: 0 ~ 2. */
} adc_arbiter_t;
/**
* @brief ADC arbiter default configuration.
*
* @note ESP32S2: Only ADC2 supports (needs) an arbiter.
*/
#define ADC_ARBITER_CONFIG_DEFAULT() { \
.mode = ADC_ARB_MODE_FIX, \
.rtc_pri = 1, \
.dig_pri = 0, \
.pwdet_pri = 2, \
}
/**
* @brief ADC digital controller (DMA mode) filter index options.
*
* @note For ESP32-S2, The filter object of the ADC is fixed.
*/
typedef enum {
ADC_DIGI_FILTER_IDX0 = 0, /*!<The filter index 0.
For ESP32-S2, It can only be used to filter all enabled channels of ADC1 unit at the same time. */
ADC_DIGI_FILTER_IDX1, /*!<The filter index 1.
For ESP32-S2, It can only be used to filter all enabled channels of ADC2 unit at the same time. */
ADC_DIGI_FILTER_IDX_MAX
} adc_digi_filter_idx_t;
/**
* @brief ADC digital controller (DMA mode) filter type options.
* Expression: filter_data = (k-1)/k * last_data + new_data / k.
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32C3
ADC_DIGI_FILTER_DIS = -1, /*!< Disable filter */
#endif
ADC_DIGI_FILTER_IIR_2 = 0, /*!<The filter mode is first-order IIR filter. The coefficient is 2. */
ADC_DIGI_FILTER_IIR_4, /*!<The filter mode is first-order IIR filter. The coefficient is 4. */
ADC_DIGI_FILTER_IIR_8, /*!<The filter mode is first-order IIR filter. The coefficient is 8. */
ADC_DIGI_FILTER_IIR_16, /*!<The filter mode is first-order IIR filter. The coefficient is 16. */
ADC_DIGI_FILTER_IIR_64, /*!<The filter mode is first-order IIR filter. The coefficient is 64. */
ADC_DIGI_FILTER_IIR_MAX
} adc_digi_filter_mode_t;
/**
* @brief ADC digital controller (DMA mode) filter configuration.
*
* @note For ESP32-S2, The filter object of the ADC is fixed.
* @note For ESP32-S2, The filter object is always all enabled channels.
*/
typedef struct {
adc_unit_t adc_unit; /*!<Set adc unit number for filter.
For ESP32-S2, Filter IDX0/IDX1 can only be used to filter all enabled channels of ADC1/ADC2 unit at the same time. */
adc_channel_t channel; /*!<Set adc channel number for filter.
For ESP32-S2, it's always `ADC_CHANNEL_MAX` */
adc_digi_filter_mode_t mode;/*!<Set adc filter mode for filter. See ``adc_digi_filter_mode_t``. */
} adc_digi_filter_t;
/**
* @brief ADC digital controller (DMA mode) monitor index options.
*
* @note For ESP32-S2, The monitor object of the ADC is fixed.
*/
typedef enum {
ADC_DIGI_MONITOR_IDX0 = 0, /*!<The monitor index 0.
For ESP32-S2, It can only be used to monitor all enabled channels of ADC1 unit at the same time. */
ADC_DIGI_MONITOR_IDX1, /*!<The monitor index 1.
For ESP32-S2, It can only be used to monitor all enabled channels of ADC2 unit at the same time. */
ADC_DIGI_MONITOR_IDX_MAX
} adc_digi_monitor_idx_t;
/**
* @brief Set monitor mode of adc digital controller.
* MONITOR_HIGH:If ADC_OUT > threshold, Generates monitor interrupt.
* MONITOR_LOW: If ADC_OUT < threshold, Generates monitor interrupt.
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32C3
ADC_DIGI_MONITOR_DIS = 0, /*!<Disable monitor. */
ADC_DIGI_MONITOR_EN, /*!<If ADC_OUT < threshold, Generates monitor interrupt. */
/*!<If ADC_OUT > threshold, Generates monitor interrupt. */
#else
ADC_DIGI_MONITOR_HIGH = 0, /*!<If ADC_OUT > threshold, Generates monitor interrupt. */
ADC_DIGI_MONITOR_LOW, /*!<If ADC_OUT < threshold, Generates monitor interrupt. */
#endif
ADC_DIGI_MONITOR_MAX
} adc_digi_monitor_mode_t;
/**
* @brief ADC digital controller (DMA mode) monitor configuration.
*
* @note For ESP32-S2, The monitor object of the ADC is fixed.
* @note For ESP32-S2, The monitor object is always all enabled channels.
*/
typedef struct {
adc_unit_t adc_unit; /*!<Set adc unit number for monitor.
For ESP32-S2, monitor IDX0/IDX1 can only be used to monitor all enabled channels of ADC1/ADC2 unit at the same time. */
adc_channel_t channel; /*!<Set adc channel number for monitor.
For ESP32-S2, it's always `ADC_CHANNEL_MAX` */
adc_digi_monitor_mode_t mode; /*!<Set adc monitor mode. See ``adc_digi_monitor_mode_t``. */
#if CONFIG_IDF_TARGET_ESP32C3
uint32_t h_threshold; /*!<Set monitor threshold of adc digital controller. */
uint32_t l_threshold; /*!<Set monitor threshold of adc digital controller. */
#else
uint32_t threshold; /*!<Set monitor threshold of adc digital controller. */
#endif
} adc_digi_monitor_t;
#endif // CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3

View File

@@ -0,0 +1,157 @@
// Copyright 2020 Espressif Systems (shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "hal/aes_types.h"
#include "hal/aes_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Sets the key used for AES encryption/decryption
*
* @param key pointer to the key
* @param key_bytes number of bytes in key
* @param mode key mode, 0 : decrypt, 1: encrypt
*
* @return uint8_t number of key bytes written to hardware, used for fault injection check
*/
uint8_t aes_hal_setkey(const uint8_t *key, size_t key_bytes, int mode);
/**
* @brief encrypts/decrypts a single block
*
* @param input_block input block, size of AES_BLOCK_BYTES
* @param output_block output block, size of AES_BLOCK_BYTES
*/
void aes_hal_transform_block(const void *input_block, void *output_block);
#if SOC_AES_SUPPORT_DMA
/**
* @brief Inits the AES mode of operation
*
* @param mode mode of operation, e.g. CTR or CBC
*/
void aes_hal_mode_init(esp_aes_mode_t mode);
/**
* @brief Sets the initialization vector for the transform
*
* @note The same IV must never be reused with the same key
*
* @param iv the initialization vector, length = IV_BYTES (16 bytes)
*/
void aes_hal_set_iv(const uint8_t *iv);
/**
* @brief Reads the initialization vector
*
* @param iv initialization vector read from HW, length = IV_BYTES (16 bytes)
*/
void aes_hal_read_iv(uint8_t *iv);
/**
* @brief Busy waits until the AES operation is done
*
* @param output pointer to inlink descriptor
*/
void aes_hal_wait_done(void);
/**
* @brief Starts an already configured AES DMA transform
*
* @param num_blocks Number of blocks to transform
*/
void aes_hal_transform_dma_start(size_t num_blocks);
/**
* @brief Finish up a AES DMA conversion, release DMA
*
*/
void aes_hal_transform_dma_finish(void);
/**
* @brief Enable or disable transform completed interrupt
*
* @param enable true to enable, false to disable.
*/
#define aes_hal_interrupt_enable(enable) aes_ll_interrupt_enable(enable)
/**
* @brief Clears the interrupt
*
*/
#define aes_hal_interrupt_clear() aes_ll_interrupt_clear()
#if SOC_AES_SUPPORT_GCM
/**
* @brief Calculates the Hash sub-key H0 needed to start AES-GCM
*
* @param gcm_hash the Hash sub-key H0 output
*/
void aes_hal_gcm_calc_hash(uint8_t *gcm_hash);
/**
* @brief Initializes the AES hardware for AES-GCM
*
* @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks
* @param num_valid_bit the number of effective bits of incomplete blocks in plaintext/cipertext
*/
void aes_hal_gcm_init(size_t aad_num_blocks, size_t num_valid_bit);
/**
* @brief Starts a AES-GCM transform
*
* @param num_blocks Number of blocks to transform
*/
void aes_hal_transform_dma_gcm_start(size_t num_blocks);
/**
* @brief Sets the J0 value, for more information see the GCM subchapter in the TRM
*
* @note Only affects AES-GCM
*
* @param j0 J0 value
*/
#define aes_hal_gcm_set_j0(j0) aes_ll_gcm_set_j0(j0)
/**
* @brief Read the tag after a AES-GCM transform
*
* @param tag Pointer to where to store the result
* @param tag_length number of bytes to read into tag
*/
void aes_hal_gcm_read_tag(uint8_t *tag, size_t tag_len);
#endif //SOC_AES_SUPPORT_GCM
#endif //SOC_AES_SUPPORT_DMA
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,48 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/* padlock.c and aesni.c rely on these values! */
#define ESP_AES_ENCRYPT 1
#define ESP_AES_DECRYPT 0
/* DMA AES working modes*/
typedef enum {
ESP_AES_BLOCK_MODE_ECB = 0,
ESP_AES_BLOCK_MODE_CBC,
ESP_AES_BLOCK_MODE_OFB,
ESP_AES_BLOCK_MODE_CTR,
ESP_AES_BLOCK_MODE_CFB8,
ESP_AES_BLOCK_MODE_CFB128,
ESP_AES_BLOCK_MODE_GCM,
ESP_AES_BLOCK_MODE_MAX,
} esp_aes_mode_t;
/* Number of bytes in an AES block */
#define AES_BLOCK_BYTES (16)
/* Number of words in an AES block */
#define AES_BLOCK_WORDS (4)
/* Number of bytes in an IV */
#define IV_BYTES (16)
/* Number of words in an IV */
#define IV_WORDS (4)
/* Number of bytes in a GCM tag block */
#define TAG_BYTES (16)
/* Number of words in a GCM tag block */
#define TAG_WORDS (4)
#define AES_128_KEY_BYTES (128/8)
#define AES_192_KEY_BYTES (192/8)
#define AES_256_KEY_BYTES (256/8)

View File

@@ -0,0 +1,48 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "soc/soc_caps.h"
typedef struct {
uint8_t threshold;
bool enabled;
bool reset_enabled;
bool flash_power_down;
bool rf_power_down;
} brownout_hal_config_t;
void brownout_hal_config(const brownout_hal_config_t *cfg);
void brownout_hal_intr_enable(bool enable);
void brownout_hal_intr_clear(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,132 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/cpu_types.h"
#include "hal/cpu_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Return the ID of the core currently executing this code.
*
* @return core id [0..SOC_CPU_CORES_NUM - 1]
*/
#define cpu_hal_get_core_id() cpu_ll_get_core_id()
/**
* Get the current value of the stack pointer.
*
* @return the current stack pointer
*/
#define cpu_hal_get_sp() cpu_ll_get_sp()
/**
* Get the current value of the internal counter that increments
* every processor-clock cycle.
*
* @return cycle count; returns 0 if not supported
*/
#define cpu_hal_get_cycle_count() cpu_ll_get_cycle_count()
/**
* Set the given value into the internal counter that increments
* every processor-clock cycle.
*/
#define cpu_hal_set_cycle_count(val) cpu_ll_set_cycle_count(val)
/**
* Check if some form of debugger is attached to CPU.
*
* @return true debugger is attached
* @return false no debugger is attached/ no support for debuggers
*/
#define cpu_hal_is_debugger_attached() cpu_ll_is_debugger_attached()
/**
* Init HW loop status.
*/
#define cpu_hal_init_hwloop() cpu_ll_init_hwloop()
/**
* Trigger a call to debugger.
*/
#define cpu_hal_break() cpu_ll_break()
/**
* Wait for interrupt.
*/
#define cpu_hal_waiti() cpu_ll_waiti()
#if SOC_CPU_BREAKPOINTS_NUM > 0
/**
* Set and enable breakpoint at an instruction address.
*
* @note Overwrites previously set breakpoint with same breakpoint ID.
*
* @param id breakpoint to set [0..SOC_CPU_BREAKPOINTS_NUM - 1]
* @param addr address to set a breakpoint on
*/
void cpu_hal_set_breakpoint(int id, const void* addr);
/**
* Clear and disable breakpoint.
*
* @param id breakpoint to clear [0..SOC_CPU_BREAKPOINTS_NUM - 1]
*/
void cpu_hal_clear_breakpoint(int id);
#endif // SOC_CPU_BREAKPOINTS_NUM > 0
#if SOC_CPU_WATCHPOINTS_NUM > 0
/**
* Set and enable a watchpoint, specifying the memory range and trigger operation.
*
* @param id watchpoint to set [0..SOC_CPU_WATCHPOINTS_NUM - 1]
* @param addr starting address
* @param size number of bytes from starting address to watch
* @param trigger operation on specified memory range that triggers the watchpoint (read, write, read/write)
*/
void cpu_hal_set_watchpoint(int id, const void* addr, size_t size, watchpoint_trigger_t trigger);
/**
* Clear and disable watchpoint.
*
* @param id watchpoint to clear [0..SOC_CPU_WATCHPOINTS_NUM - 1]
*/
void cpu_hal_clear_watchpoint(int id);
#endif // SOC_CPU_WATCHPOINTS_NUM > 0
/**
* Set exception vector table base address.
*
* @param base address to move the exception vector table to
*/
void cpu_hal_set_vecbase(const void* base);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,21 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
typedef enum {
WATCHPOINT_TRIGGER_ON_RO, // on read
WATCHPOINT_TRIGGER_ON_WO, // on write
WATCHPOINT_TRIGGER_ON_RW // on either read or write
} watchpoint_trigger_t;

View File

@@ -0,0 +1,80 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
#pragma once
#include "hal/dac_ll.h"
#include "hal/hal_defs.h"
#include <esp_err.h>
/**
* Power on dac module and start output voltage.
*
* @note Before powering up, make sure the DAC PAD is set to RTC PAD and floating status.
* @param channel DAC channel num.
*/
#define dac_hal_power_on(channel) dac_ll_power_on(channel)
/**
* Power done dac module and stop output voltage.
*
* @param channel DAC channel num.
*/
#define dac_hal_power_down(channel) dac_ll_power_down(channel)
/**
* Enable/disable the synchronization operation function of ADC1 and DAC.
*
* @note If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage.
*
* @param enable Enable or disable adc and dac synchronization function.
*/
#define dac_hal_rtc_sync_by_adc(enable) dac_ll_rtc_sync_by_adc(enable)
/**
* Output voltage with value (8 bit).
*
* @param channel DAC channel num.
* @param value Output value. Value range: 0 ~ 255.
* The corresponding range of voltage is 0v ~ VDD3P3_RTC.
*/
#define dac_hal_update_output_value(channel, value) dac_ll_update_output_value(channel, value)
/**
* Enable cosine wave generator output.
*/
#define dac_hal_cw_generator_enable() dac_ll_cw_generator_enable()
/**
* Disable cosine wave generator output.
*/
#define dac_hal_cw_generator_disable() dac_ll_cw_generator_disable()
/**
* Config the cosine wave generator function in DAC module.
*
* @param cw Configuration.
*/
void dac_hal_cw_generator_config(dac_cw_config_t *cw);
/**
* Enable/disable DAC output data from DMA.
*/
#define dac_hal_digi_enable_dma(enable) dac_ll_digi_enable_dma(enable)

View File

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

View File

@@ -0,0 +1,45 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @brief Type of DMA descriptor
*
*/
typedef struct dma_descriptor_s {
struct {
uint32_t size : 12; /*!< Buffer size */
uint32_t length : 12; /*!< Number of valid bytes in the buffer */
uint32_t reversed24_27 : 4; /*!< Reserved */
uint32_t err_eof : 1; /*!< Whether the received buffer contains error */
uint32_t reserved29 : 1; /*!< Reserved */
uint32_t suc_eof : 1; /*!< Whether the descriptor is the last one in the link */
uint32_t owner : 1; /*!< Who is allowed to access the buffer that this descriptor points to */
} dw0; /*!< Descriptor Word 0 */
void *buffer; /*!< Pointer to the buffer */
struct dma_descriptor_s *next; /*!< Pointer to the next descriptor (set to NULL if the descriptor is the last one, e.g. suc_eof=1) */
} dma_descriptor_t;
_Static_assert(sizeof(dma_descriptor_t) == 12, "dma_descriptor_t should occupy 12 bytes in memory");
#define DMA_DESCRIPTOR_BUFFER_OWNER_CPU (0) /*!< DMA buffer is allowed to be accessed by CPU */
#define DMA_DESCRIPTOR_BUFFER_OWNER_DMA (1) /*!< DMA buffer is allowed to be accessed by DMA engine */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */

View File

@@ -0,0 +1,112 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#if CONFIG_IDF_TARGET_ESP32
#error "ESP32 doesn't have a DS peripheral"
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The result when checking whether the key to decrypt the RSA parameters is ready.
*/
typedef enum {
DS_KEY_INPUT_OK = 0, /**< The decryption key is ready. */
DS_NO_KEY_INPUT, /**< Dependent peripheral providing key hasn't been activated. */
DS_OTHER_WRONG, /**< Dependent peripheral running but problem receiving the key. */
} ds_key_check_t;
typedef enum {
DS_SIGNATURE_OK = 0, /**< Signature is valid and can be read. */
DS_SIGNATURE_PADDING_FAIL = 1, /**< Padding invalid, signature can be read if user wants it. */
DS_SIGNATURE_MD_FAIL = 2, /**< Message digest check failed, signature invalid. */
DS_SIGNATURE_PADDING_AND_MD_FAIL = 3, /**< Both padding and MD check failed. */
} ds_signature_check_t;
/**
* @brief Start the whole signing process after the input key is ready.
*
* Call this before using any of the functions below. The input key is ready must be ready at this point.
*/
void ds_hal_start(void);
/**
* @brief Finish the whole signing process. Call this after the signature is read or in case of an error.
*/
void ds_hal_finish(void);
/**
* @brief Check whether the key input (HMAC on ESP32-C3) is correct.
*/
ds_key_check_t ds_hal_check_decryption_key(void);
/**
* @brief Write the initialization vector.
*/
void ds_hal_configure_iv(const uint32_t *iv);
/**
* @brief Write the message which should be signed.
*
* @param msg Pointer to the message.
* @param size Length of signature result in bytes. It is the RSA signature length in bytes.
*/
void ds_hal_write_message(const uint8_t *msg, size_t size);
/**
* @brief Write the encrypted private key parameters.
*/
void ds_hal_write_private_key_params(const uint8_t *block);
/**
* @brief Begin signing procedure.
*/
void ds_hal_start_sign(void);
/**
* @brief Check whether the hardware is busy with an operation.
*
* @return True if the hardware has finished the signing procedure, otherwise false.
*/
bool ds_hal_busy(void);
/**
* @brief Check and read the signature from the hardware.
*
* @return
* - DS_SIGNATURE_OK if no issue is detected with the signature.
* - DS_SIGNATURE_PADDING_FAIL if the padding of the private key parameters is wrong.
* - DS_SIGNATURE_MD_FAIL if the message digest check failed. This means that the message digest calculated using
* the private key parameters fails, i.e., the integrity of the private key parameters is not protected.
* - DS_SIGNATURE_PADDING_AND_MD_FAIL if both padding and message digest check fail.
*/
ds_signature_check_t ds_hal_read_result(uint8_t *result, size_t size);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,48 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Possible errors returned from esp flash internal functions, these error codes
* should be consistent with esp_err_t codes. But in order to make the source
* files less dependent to esp_err_t, they use the error codes defined in this
* replacable header. This header should ensure the consistency to esp_err_t.
*/
enum {
/* These codes should be consistent with esp_err_t errors. However, error codes with the same values are not
* allowed in ESP-IDF. This is a workaround in order to not introduce a dependency between the "soc" and
* "esp_common" components. The disadvantage is that the output of esp_err_to_name(ESP_ERR_FLASH_SIZE_NOT_MATCH)
* will be ESP_ERR_INVALID_SIZE. */
ESP_ERR_FLASH_SIZE_NOT_MATCH = ESP_ERR_INVALID_SIZE, ///< The chip doesn't have enough space for the current partition table
ESP_ERR_FLASH_NO_RESPONSE = ESP_ERR_INVALID_RESPONSE, ///< Chip did not respond to the command, or timed out.
};
//The ROM code has already taken 1 and 2, to avoid possible conflicts, start from 3.
#define ESP_ERR_FLASH_NOT_INITIALISED (ESP_ERR_FLASH_BASE+3) ///< esp_flash_chip_t structure not correctly initialised by esp_flash_init().
#define ESP_ERR_FLASH_UNSUPPORTED_HOST (ESP_ERR_FLASH_BASE+4) ///< Requested operation isn't supported via this host SPI bus (chip->spi field).
#define ESP_ERR_FLASH_UNSUPPORTED_CHIP (ESP_ERR_FLASH_BASE+5) ///< Requested operation isn't supported by this model of SPI flash chip.
#define ESP_ERR_FLASH_PROTECTED (ESP_ERR_FLASH_BASE+6) ///< Write operation failed due to chip's write protection being enabled.
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,37 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in soc/README.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/gdma_struct.h"
typedef struct {
gdma_dev_t *dev;
} gdma_hal_context_t;
void gdma_hal_init(gdma_hal_context_t *hal, int group_id);
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,30 @@
// Copyright 2010-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp_log.h"
// platform related stuff
#define HAL_SWAP32(word) __builtin_bswap32(word)
#define HAL_SWAP64(word) __builtin_bswap64(word)
#define HAL_LOGE(...) ESP_LOGE(__VA_ARGS__)
#define HAL_LOGW(...) ESP_LOGW(__VA_ARGS__)
#define HAL_LOGI(...) ESP_LOGI(__VA_ARGS__)
#define HAL_LOGD(...) ESP_LOGD(__VA_ARGS__)
#define HAL_LOGV(...) ESP_LOGV(__VA_ARGS__)
#define STATIC_HAL_REG_CHECK(TAG, ENUM, VAL) _Static_assert((ENUM) == (VAL), #TAG" "#ENUM" definition no longer matches register value")

View File

@@ -0,0 +1,534 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for I2C
#pragma once
#include "hal/i2c_ll.h"
#include "hal/i2c_types.h"
/**
* @brief I2C hal Context definition
*/
typedef struct {
i2c_dev_t *dev;
uint32_t version;
} i2c_hal_context_t;
/**
* @brief Write the I2C rxfifo with the given length
*
* @param hal Context of the HAL layer
* @param wr_data Pointer to data buffer
* @param wr_size Amount of data needs write
*
* @return None
*/
#define i2c_hal_write_txfifo(hal,wr_data,wr_size) i2c_ll_write_txfifo((hal)->dev,wr_data,wr_size)
/**
* @brief Read the I2C rxfifo with the given length
*
* @param hal Context of the HAL layer
* @param buf Pointer to data buffer
* @param rd_size Amount of data needs read
*
* @return None
*/
#define i2c_hal_read_rxfifo(hal,buf,rd_size) i2c_ll_read_rxfifo((hal)->dev,buf,rd_size)
/**
* @brief Write I2C cmd register
*
* @param hal Context of the HAL layer
* @param cmd I2C hardware command
* @param cmd_idx The index of the command register, should be less than 16
*
* @return None
*/
#define i2c_hal_write_cmd_reg(hal,cmd, cmd_idx) i2c_ll_write_cmd_reg((hal)->dev,cmd,cmd_idx)
/**
* @brief Configure the I2C to triger a trasaction
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_trans_start(hal) i2c_ll_trans_start((hal)->dev)
/**
* @brief Enable I2C master RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_enable_master_rx_it(hal) i2c_ll_master_enable_rx_it((hal)->dev)
/**
* @brief Enable I2C master TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_enable_master_tx_it(hal) i2c_ll_master_enable_tx_it((hal)->dev)
/**
* @brief Clear I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_slave_clr_tx_it(hal) i2c_ll_slave_clr_tx_it((hal)->dev)
/**
* @brief Clear I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define i2c_hal_slave_clr_rx_it(hal) i2c_ll_slave_clr_rx_it((hal)->dev)
/**
* @brief Init the I2C master.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number
*
* @return None
*/
void i2c_hal_master_init(i2c_hal_context_t *hal, i2c_port_t i2c_num);
/**
* @brief Init the I2C slave.
*
* @param hal Context of the HAL layer
* @param i2c_num I2C port number
*
* @return None
*/
void i2c_hal_slave_init(i2c_hal_context_t *hal, i2c_port_t i2c_num);
/**
* @brief Reset the I2C hw txfifo
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_txfifo_rst(i2c_hal_context_t *hal);
/**
* @brief Reset the I2C hw rxfifo
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_rxfifo_rst(i2c_hal_context_t *hal);
/**
* @brief Configure the I2C data MSB bit shifted first or LSB bit shifted first.
*
* @param hal Context of the HAL layer
* @param tx_mode Data format of TX
* @param rx_mode Data format of RX
*
* @return None
*/
void i2c_hal_set_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t tx_mode, i2c_trans_mode_t rx_mode);
/**
* @brief Configure the I2C hardware filter function.
*
* @param hal Context of the HAL layer
* @param filter_num If the glitch period on the line is less than this value(in APB cycle), it will be filtered out
* If `filter_num == 0`, the filter will be disabled
*
* @return None
*/
void i2c_hal_set_filter(i2c_hal_context_t *hal, uint8_t filter_num);
/**
* @brief Get the I2C hardware filter configuration
*
* @param hal Context of the HAL layer
* @param filter_num Pointer to accept the hardware filter configuration
*
* @return None
*/
void i2c_hal_get_filter(i2c_hal_context_t *hal, uint8_t *filter_num);
/**
* @brief Configure the I2C SCL timing
*
* @param hal Context of the HAL layer
* @param hight_period SCL high period
* @param low_period SCL low period
*
* @return None
*/
void i2c_hal_set_scl_timing(i2c_hal_context_t *hal, int hight_period, int low_period);
/**
* @brief Configure the I2C master SCL frequency
*
* @param hal Context of the HAL layer
* @param src_clk The I2C Source clock frequency
* @param scl_freq The SCL frequency to be set
*
* @return None
*/
void i2c_hal_set_scl_freq(i2c_hal_context_t *hal, uint32_t src_clk, uint32_t scl_freq);
/**
* @brief Clear the I2C interrupt status with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be clearned
*
* @return None
*/
void i2c_hal_clr_intsts_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Enable the I2C interrupt with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be enabled
*
* @return None
*/
void i2c_hal_enable_intr_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Disable the I2C interrupt with the given mask
*
* @param hal Context of the HAL layer
* @param mask The interrupt bitmap needs to be disabled
*
* @return None
*/
void i2c_hal_disable_intr_mask(i2c_hal_context_t *hal, uint32_t mask);
/**
* @brief Configure the I2C memory access mode, FIFO mode or none FIFO mode
*
* @param hal Context of the HAL layer
* @param fifo_mode_en Set true to enable FIFO access mode, else set it false
*
* @return None
*/
void i2c_hal_set_fifo_mode(i2c_hal_context_t *hal, bool fifo_mode_en);
/**
* @brief Configure the I2C timeout value
*
* @param hal Context of the HAL layer
* @param tout_val the timeout value to be set
*
* @return None
*/
void i2c_hal_set_tout(i2c_hal_context_t *hal, int tout_val);
/**
* @brief Get the I2C time out configuration
*
* @param tout_val Pointer to accept the timeout configuration
*
* @return None
*/
void i2c_hal_get_tout(i2c_hal_context_t *hal, int *tout_val);
/**
* @brief Configure the I2C slave address
*
* @param hal Context of the HAL layer
* @param slave_addr Slave address
* @param addr_10bit_en Set true to enable 10-bit slave address mode, Set false to enable 7-bit address mode
*
* @return None
*/
void i2c_hal_set_slave_addr(i2c_hal_context_t *hal, uint16_t slave_addr, bool addr_10bit_en);
/**
* @brief Configure the I2C stop timing
*
* @param hal Context of the HAL layer
* @param stop_setup The stop condition setup period (in APB cycle)
* @param stop_hold The stop condition hold period (in APB cycle)
*
* @return None
*/
void i2c_hal_set_stop_timing(i2c_hal_context_t *hal, int stop_setup, int stop_hold);
/**
* @brief Configure the I2C start timing
*
* @param hal Context of the HAL layer
* @param start_setup The start condition setup period (in APB cycle)
* @param start_hold The start condition hold period (in APB cycle)
*
* @return None
*/
void i2c_hal_set_start_timing(i2c_hal_context_t *hal, int start_setup, int start_hold);
/**
* @brief Configure the I2C sda sample timing
*
* @param hal Context of the HAL layer
* @param sda_sample The SDA sample time (in APB cycle)
* @param sda_hold The SDA hold time (in APB cycle)
*
* @return None
*/
void i2c_hal_set_sda_timing(i2c_hal_context_t *hal, int sda_sample, int sda_hold);
/**
* @brief Configure the I2C txfifo empty threshold value
*
* @param hal Context of the HAL layer.
* @param empty_thr TxFIFO empty threshold value
*
* @return None
*/
void i2c_hal_set_txfifo_empty_thr(i2c_hal_context_t *hal, uint8_t empty_thr);
/**
* @brief Configure the I2C rxfifo full threshold value
*
* @param hal Context of the HAL layer
* @param full_thr RxFIFO full threshold value
*
* @return None
*/
void i2c_hal_set_rxfifo_full_thr(i2c_hal_context_t *hal, uint8_t full_thr);
/**
* @brief Get the I2C interrupt status
*
* @param hal Context of the HAL layer
* @param mask Pointer to accept the interrupt status
*
* @return None
*/
void i2c_hal_get_intsts_mask(i2c_hal_context_t *hal, uint32_t *mask);
/**
* @brief Check if the I2C bus is busy
*
* @param hal Context of the HAL layer
*
* @return True if the bus is busy, otherwise, fale will be returned
*/
bool i2c_hal_is_bus_busy(i2c_hal_context_t *hal);
/**
* @brief Get the I2C sda sample timing configuration
*
* @param hal Context of the HAL layer
* @param sample_time Pointer to accept the SDA sample time
* @param hold_time Pointer to accept the SDA hold time
*
* @return None
*/
void i2c_hal_get_sda_timing(i2c_hal_context_t *hal, int *sample_time, int *hold_time);
/**
* @brief Get the I2C stop timing configuration
*
* @param hal Context of the HAL layer
* @param setup_time Pointer to accept the stop condition setup period
* @param hold_time Pointer to accept the stop condition hold period
*
* @return None
*/
void i2c_hal_get_stop_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time);
/**
* @brief Get the I2C scl timing configuration
*
* @param hal Context of the HAL layer
* @param high_period Pointer to accept the scl high period
* @param low_period Pointer to accept the scl low period
*
* @return None
*/
void i2c_hal_get_scl_timing(i2c_hal_context_t *hal, int *high_period, int *low_period);
/**
* @brief Get the I2C start timing configuration
*
* @param hal Context of the HAL layer
* @param setup_time Pointer to accept the start condition setup period
* @param hold_time Pointer to accept the start condition hold period
*
* @return None
*/
void i2c_hal_get_start_timing(i2c_hal_context_t *hal, int *setup_time, int *hold_time);
/**
* @brief Check if the I2C is master mode
*
* @param hal Context of the HAL layer
*
* @return True if in master mode, otherwise, false will be returned
*/
bool i2c_hal_is_master_mode(i2c_hal_context_t *hal);
/**
* @brief Get the rxFIFO readable length
*
* @param hal Context of the HAL layer
* @param len Pointer to accept the rxFIFO readable length
*
* @return None
*/
void i2c_hal_get_rxfifo_cnt(i2c_hal_context_t *hal, uint32_t *len);
/**
* @brief Set I2C bus timing with the given frequency
*
* @param hal Context of the HAL layer
* @param scl_freq The scl frequency to be set
* @param src_clk Source clock of I2C
*
* @return None
*/
void i2c_hal_set_bus_timing(i2c_hal_context_t *hal, int scl_freq, i2c_sclk_t src_clk);
/**
* @brief Get I2C txFIFO writeable length
*
* @param hal Context of the HAL layer
* @param len Pointer to accept the txFIFO writeable length
*
* @return None
*/
void i2c_hal_get_txfifo_cnt(i2c_hal_context_t *hal, uint32_t *len);
/**
* @brief Check if the I2C is master mode
*
* @param hal Context of the HAL layer
* @param tx_mode Pointer to accept the TX data mode
* @param rx_mode Pointer to accept the RX data mode
*
* @return None
*/
void i2c_hal_get_data_mode(i2c_hal_context_t *hal, i2c_trans_mode_t *tx_mode, i2c_trans_mode_t *rx_mode);
/**
* @brief I2C hardware FSM reset
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_master_fsm_rst(i2c_hal_context_t *hal);
/**
* @brief @brief Clear I2C bus
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_master_clr_bus(i2c_hal_context_t *hal);
/**
* @brief Enable I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_enable_slave_tx_it(i2c_hal_context_t *hal);
/**
* @brief Disable I2C slave TX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_disable_slave_tx_it(i2c_hal_context_t *hal);
/**
* @brief Enable I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_enable_slave_rx_it(i2c_hal_context_t *hal);
/**
* @brief Disable I2C slave RX interrupt
*
* @param hal Context of the HAL layer
*
* @return None
*/
void i2c_hal_disable_slave_rx_it(i2c_hal_context_t *hal);
/**
* @brief I2C master handle tx interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_master_handle_tx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief I2C master handle rx interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_master_handle_rx_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief I2C slave handle interrupt event
*
* @param hal Context of the HAL layer
* @param event Pointer to accept the interrupt event
*
* @return None
*/
void i2c_hal_slave_handle_event(i2c_hal_context_t *hal, i2c_intr_event_t *event);
/**
* @brief Synchronize I2C status
*
* @param hal Context of the HAL layer
*
* @return None
*
*/
void i2c_hal_update_config(i2c_hal_context_t *hal);

View File

@@ -0,0 +1,124 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
/**
* @brief I2C port number, can be I2C_NUM_0 ~ (I2C_NUM_MAX-1).
*/
typedef int i2c_port_t;
typedef enum{
I2C_MODE_SLAVE = 0, /*!< I2C slave mode */
I2C_MODE_MASTER, /*!< I2C master mode */
I2C_MODE_MAX,
} i2c_mode_t;
typedef enum {
I2C_MASTER_WRITE = 0, /*!< I2C write data */
I2C_MASTER_READ, /*!< I2C read data */
} i2c_rw_t;
typedef enum {
I2C_DATA_MODE_MSB_FIRST = 0, /*!< I2C data msb first */
I2C_DATA_MODE_LSB_FIRST = 1, /*!< I2C data lsb first */
I2C_DATA_MODE_MAX
} i2c_trans_mode_t;
typedef enum {
I2C_ADDR_BIT_7 = 0, /*!< I2C 7bit address for slave mode */
I2C_ADDR_BIT_10, /*!< I2C 10bit address for slave mode */
I2C_ADDR_BIT_MAX,
} i2c_addr_mode_t;
typedef enum {
I2C_MASTER_ACK = 0x0, /*!< I2C ack for each byte read */
I2C_MASTER_NACK = 0x1, /*!< I2C nack for each byte read */
I2C_MASTER_LAST_NACK = 0x2, /*!< I2C nack for the last byte*/
I2C_MASTER_ACK_MAX,
} i2c_ack_type_t;
/**
* @brief I2C clock source, sorting from smallest to largest,
* place them in order.
* This can be expanded in the future use.
*/
typedef enum {
I2C_SCLK_DEFAULT = 0, /*!< I2C source clock not selected*/
#if SOC_I2C_SUPPORT_APB
I2C_SCLK_APB, /*!< I2C source clock from APB, 80M*/
#endif
#if SOC_I2C_SUPPORT_XTAL
I2C_SCLK_XTAL, /*!< I2C source clock from XTAL, 40M */
#endif
#if SOC_I2C_SUPPORT_RTC
I2C_SCLK_RTC, /*!< I2C source clock from 8M RTC, 8M */
#endif
#if SOC_I2C_SUPPORT_REF_TICK
I2C_SCLK_REF_TICK, /*!< I2C source clock from REF_TICK, 1M */
#endif
I2C_SCLK_MAX,
} i2c_sclk_t;
// I2C clk flags for users to use, can be expanded in the future.
#define I2C_SCLK_SRC_FLAG_FOR_NOMAL (0) /*!< Any one clock source that is available for the specified frequency may be choosen*/
#define I2C_SCLK_SRC_FLAG_AWARE_DFS (1 << 0) /*!< For REF tick clock, it won't change with APB.*/
#define I2C_SCLK_SRC_FLAG_LIGHT_SLEEP (1 << 1) /*!< For light sleep mode.*/
/// Use the highest speed that is available for the clock source picked by clk_flags
#define I2C_CLK_FREQ_MAX (-1)
/**
* @brief I2C initialization parameters
*/
typedef struct{
i2c_mode_t mode; /*!< I2C mode */
int sda_io_num; /*!< GPIO number for I2C sda signal */
int scl_io_num; /*!< GPIO number for I2C scl signal */
bool sda_pullup_en; /*!< Internal GPIO pull mode for I2C sda signal*/
bool scl_pullup_en; /*!< Internal GPIO pull mode for I2C scl signal*/
union {
struct {
uint32_t clk_speed; /*!< I2C clock frequency for master mode, (no higher than 1MHz for now) */
} master; /*!< I2C master config */
struct {
uint8_t addr_10bit_en; /*!< I2C 10bit address mode enable for slave mode */
uint16_t slave_addr; /*!< I2C address for slave mode */
} slave; /*!< I2C slave config */
};
uint32_t clk_flags; /*!< Bitwise of ``I2C_SCLK_SRC_FLAG_**FOR_DFS**`` for clk source choice*/
} i2c_config_t;
#if CONFIG_IDF_TARGET_ESP32
typedef enum{
I2C_CMD_RESTART = 0, /*!<I2C restart command */
I2C_CMD_WRITE, /*!<I2C write command */
I2C_CMD_READ, /*!<I2C read command */
I2C_CMD_STOP, /*!<I2C stop command */
I2C_CMD_END /*!<I2C end command */
} i2c_opmode_t __attribute__((deprecated));
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,300 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for I2S.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/i2s_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_ll.h"
#include "hal/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
i2s_dev_t *dev;
uint32_t version;
} i2s_hal_context_t;
/**
* @brief Get I2S interrupt status
*
* @param hal Context of the HAL layer
* @param status interrupt status
*/
#define i2s_hal_get_intr_status(hal, status) i2s_ll_get_intr_status((hal)->dev, status)
/**
* @brief Clear I2S interrupt status
*
* @param hal Context of the HAL layer
* @param mask interrupt status mask
*/
#define i2s_hal_clear_intr_status(hal, mask) i2s_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Get I2S out eof des address
*
* @param hal Context of the HAL layer
* @param addr out eof des address
*/
#define i2s_hal_get_out_eof_des_addr(hal, addr) i2s_ll_get_out_eof_des_addr((hal)->dev, addr)
/**
* @brief Get I2S in eof des address
*
* @param hal Context of the HAL layer
* @param addr in eof des address
*/
#define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_get_in_eof_des_addr((hal)->dev, addr)
/**
* @brief Enable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_rx_intr(hal) i2s_ll_enable_rx_intr((hal)->dev)
/**
* @brief Disable I2S rx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_rx_intr(hal) i2s_ll_disable_rx_intr((hal)->dev)
/**
* @brief Disable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_disable_tx_intr(hal) i2s_ll_disable_tx_intr((hal)->dev)
/**
* @brief Enable I2S tx interrupt
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_tx_intr(hal) i2s_ll_enable_tx_intr((hal)->dev)
/**
* @brief Set I2S tx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_tx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx mode
*
* @param hal Context of the HAL layer
* @param ch i2s channel
* @param bits bits per sample
*/
void i2s_hal_set_rx_mode(i2s_hal_context_t *hal, i2s_channel_t ch, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S out link address
*
* @param hal Context of the HAL layer
* @param addr out link address
*/
#define i2s_hal_set_out_link_addr(hal, addr) i2s_ll_set_out_link_addr((hal)->dev, addr)
/**
* @brief Set I2S in link
*
* @param hal Context of the HAL layer
* @param rx_eof_num in link eof num
* @param addr in link address
*/
void i2s_hal_set_in_link(i2s_hal_context_t *hal, uint32_t rx_eof_num, uint32_t addr);
/**
* @brief Set I2S clk div
*
* @param hal Context of the HAL layer
* @param div_num i2s clkm div num
* @param div_a i2s clkm div a
* @param div_b i2s clkm div b
* @param tx_bck_div tx bck div num
* @param rx_bck_div rx bck div num
*/
void i2s_hal_set_clk_div(i2s_hal_context_t *hal, int div_num, int div_a, int div_b, int tx_bck_div, int rx_bck_div);
/**
* @brief Set I2S clock sel
*
* @param hal Context of the HAL layer
* @param sel clock sel
*/
#define i2s_hal_set_clock_sel(hal, sel) i2s_ll_set_clk_sel((hal)->dev, sel)
/**
* @brief Set I2S tx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_tx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Set I2S rx bits mod
*
* @param hal Context of the HAL layer
* @param bits bit width per sample.
*/
void i2s_hal_set_rx_bits_mod(i2s_hal_context_t *hal, i2s_bits_per_sample_t bits);
/**
* @brief Reset I2S TX & RX module, including DMA and FIFO
*
* @param hal Context of the HAL layer
*/
void i2s_hal_reset(i2s_hal_context_t *hal);
/**
* @brief Start I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_tx(i2s_hal_context_t *hal);
/**
* @brief Start I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_start_rx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S tx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_tx(i2s_hal_context_t *hal);
/**
* @brief Stop I2S rx
*
* @param hal Context of the HAL layer
*/
void i2s_hal_stop_rx(i2s_hal_context_t *hal);
/**
* @brief Config I2S param
*
* @param hal Context of the HAL layer
* @param i2s_config I2S configurations - see i2s_config_t struct
*/
void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_config_t *i2s_config);
/**
* @brief Enable I2S sig loopback
*
* @param hal Context of the HAL layer
*/
#define i2s_hal_enable_sig_loopback(hal) i2s_ll_set_sig_loopback((hal)->dev, 1)
/**
* @brief Enable I2S master mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_master_mode(i2s_hal_context_t *hal);
/**
* @brief Enable I2S slave mode
*
* @param hal Context of the HAL layer
*/
void i2s_hal_enable_slave_mode(i2s_hal_context_t *hal);
/**
* @brief Init the I2S hal and set the I2S to the default configuration. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1)
*/
void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num);
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief Set I2S tx pdm
*
* @param hal Context of the HAL layer
* @param fp tx pdm fp
* @param fs tx pdm fs
*/
void i2s_hal_tx_pdm_cfg(i2s_hal_context_t *hal, uint32_t fp, uint32_t fs);
/**
* @brief Get I2S tx pdm
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
*/
void i2s_hal_rx_pdm_cfg(i2s_hal_context_t *hal, uint32_t dsr);
/**
* @brief Get I2S tx pdm configuration
*
* @param hal Context of the HAL layer
* @param fp Pointer to receive tx PDM fp configuration
* @param fs Pointer to receive tx PDM fs configuration
*/
void i2s_hal_get_tx_pdm(i2s_hal_context_t *hal, uint32_t *fp, uint32_t *fs);
/**
* @brief Get I2S rx pdm configuration
*
* @param hal Context of the HAL layer
* @param dsr rx pdm dsr
*/
void i2s_hal_get_rx_pdm(i2s_hal_context_t *hal, uint32_t *dsr);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,204 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief I2S port number, the max port number is (I2S_NUM_MAX -1).
*/
typedef enum {
I2S_NUM_0 = 0, /*!< I2S port 0 */
#if SOC_I2S_NUM > 1
I2S_NUM_1 = 1, /*!< I2S port 1 */
#endif
I2S_NUM_MAX, /*!< I2S port max */
} i2s_port_t;
/**
* @brief I2S bit width per sample.
*
*/
typedef enum {
I2S_BITS_PER_SAMPLE_8BIT = 8, /*!< I2S bits per sample: 8-bits*/
I2S_BITS_PER_SAMPLE_16BIT = 16, /*!< I2S bits per sample: 16-bits*/
I2S_BITS_PER_SAMPLE_24BIT = 24, /*!< I2S bits per sample: 24-bits*/
I2S_BITS_PER_SAMPLE_32BIT = 32, /*!< I2S bits per sample: 32-bits*/
} i2s_bits_per_sample_t;
/**
* @brief I2S channel.
*
*/
typedef enum {
I2S_CHANNEL_MONO = 1, /*!< I2S 1 channel (mono)*/
I2S_CHANNEL_STEREO = 2 /*!< I2S 2 channel (stereo)*/
} i2s_channel_t;
/**
* @brief I2S communication standard format
*
*/
typedef enum {
// In order to keep compatibility, remain the old definitions and introduce new definitions,
I2S_COMM_FORMAT_STAND_I2S = 0X01, /*!< I2S communication I2S Philips standard, data launch at second BCK*/
I2S_COMM_FORMAT_STAND_MSB = 0X03, /*!< I2S communication MSB alignment standard, data launch at first BCK*/
I2S_COMM_FORMAT_STAND_PCM_SHORT = 0x04, /*!< PCM Short standard, also known as DSP mode. The period of synchronization signal (WS) is 1 bck cycle.*/
I2S_COMM_FORMAT_STAND_PCM_LONG = 0x0C, /*!< PCM Long standard. The period of synchronization signal (WS) is channel_bit*bck cycles.*/
I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/
//old definition will be removed in the future.
I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/
I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/
I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/
I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/
} i2s_comm_format_t;
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT,
I2S_CHANNEL_FMT_ALL_LEFT,
I2S_CHANNEL_FMT_ONLY_RIGHT,
I2S_CHANNEL_FMT_ONLY_LEFT,
} i2s_channel_fmt_t;
/**
* @brief I2S Mode, defaut is I2S_MODE_MASTER | I2S_MODE_TX
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*
*/
typedef enum {
I2S_MODE_MASTER = 1, /*!< Master mode*/
I2S_MODE_SLAVE = 2, /*!< Slave mode*/
I2S_MODE_TX = 4, /*!< TX mode*/
I2S_MODE_RX = 8, /*!< RX mode*/
#if SOC_I2S_SUPPORTS_ADC_DAC
I2S_MODE_DAC_BUILT_IN = 16, /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/
I2S_MODE_ADC_BUILT_IN = 32, /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/
#endif
#if SOC_I2S_SUPPORTS_PDM
I2S_MODE_PDM = 64, /*!< PDM mode*/
#endif
} i2s_mode_t;
/**
* @brief I2S source clock
*
*/
typedef enum {
I2S_CLK_D2CLK = 0, /*!< Clock from PLL_D2_CLK(160M)*/
I2S_CLK_APLL, /*!< Clock from APLL*/
} i2s_clock_src_t;
/**
* @brief I2S configuration parameters for i2s_param_config function
*
*/
typedef struct {
i2s_mode_t mode; /*!< I2S work mode*/
int sample_rate; /*!< I2S sample rate*/
i2s_bits_per_sample_t bits_per_sample; /*!< I2S bits per sample*/
i2s_channel_fmt_t channel_format; /*!< I2S channel format */
i2s_comm_format_t communication_format; /*!< I2S communication format */
int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
int dma_buf_count; /*!< I2S DMA Buffer Count */
int dma_buf_len; /*!< I2S DMA Buffer Length */
bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */
bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */
int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/
} i2s_config_t;
/**
* @brief I2S event types
*
*/
typedef enum {
I2S_EVENT_DMA_ERROR,
I2S_EVENT_TX_DONE, /*!< I2S DMA finish sent 1 buffer*/
I2S_EVENT_RX_DONE, /*!< I2S DMA finish received 1 buffer*/
I2S_EVENT_MAX, /*!< I2S event max index*/
} i2s_event_type_t;
/**
* @brief I2S DAC mode for i2s_set_dac_mode.
*
* @note PDM and built-in DAC functions are only supported on I2S0 for current ESP32 chip.
*/
typedef enum {
I2S_DAC_CHANNEL_DISABLE = 0, /*!< Disable I2S built-in DAC signals*/
I2S_DAC_CHANNEL_RIGHT_EN = 1, /*!< Enable I2S built-in DAC right channel, maps to DAC channel 1 on GPIO25*/
I2S_DAC_CHANNEL_LEFT_EN = 2, /*!< Enable I2S built-in DAC left channel, maps to DAC channel 2 on GPIO26*/
I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/
I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/
} i2s_dac_mode_t;
/**
* @brief Event structure used in I2S event queue
*
*/
typedef struct {
i2s_event_type_t type; /*!< I2S event type */
size_t size; /*!< I2S data size for I2S_DATA event*/
} i2s_event_t;
/**
* @brief I2S pin number for i2s_set_pin
*
*/
typedef struct {
int bck_io_num; /*!< BCK in out pin*/
int ws_io_num; /*!< WS in out pin*/
int data_out_num; /*!< DATA out pin*/
int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t;
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief I2S PDM RX downsample mode
*/
typedef enum {
I2S_PDM_DSR_8S = 0, /*!< downsampling number is 8 for PDM RX mode*/
I2S_PDM_DSR_16S, /*!< downsampling number is 16 for PDM RX mode*/
I2S_PDM_DSR_MAX,
} i2s_pdm_dsr_t;
/**
* @brief PDM PCM convter enable/disable.
*
*/
typedef enum {
PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/
PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/
} pdm_pcm_conv_t;
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,207 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdbool.h>
#include "hal/interrupt_controller_types.h"
#include "hal/interrupt_controller_ll.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SOC_CPU_HAS_FLEXIBLE_INTC
/**
* @brief Gets target platform interrupt descriptor table
*
* @return Address of interrupt descriptor table
*/
__attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void);
#endif
/**
* @brief Gets the interrupt type given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt type
*/
__attribute__((pure)) int_type_t interrupt_controller_hal_desc_type(int interrupt_number);
/**
* @brief Gets the interrupt level given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt level bitmask
*/
__attribute__((pure)) int interrupt_controller_hal_desc_level(int interrupt_number);
/**
* @brief Gets the cpu flags given the interrupt number and target cpu.
*
* @param interrupt_number Interrupt number 0 to 31
* @param cpu_number CPU number between 0 and SOC_CPU_CORES_NUM - 1
* @return flags for that interrupt number
*/
__attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number);
/**
* @brief Gets the interrupt type given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt type
*/
static inline int_type_t interrupt_controller_hal_get_type(int interrupt_number)
{
return interrupt_controller_hal_desc_type(interrupt_number);
}
/**
* @brief Gets the interrupt level given an interrupt number.
*
* @param interrupt_number Interrupt number 0 to 31
* @return interrupt level bitmask
*/
static inline int interrupt_controller_hal_get_level(int interrupt_number)
{
return interrupt_controller_hal_desc_level(interrupt_number);
}
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/**
* @brief Set the type of an interrupt in the controller.
*
* @param interrupt_number Interrupt number 0 to 31
* @param type interrupt type as edge or level triggered
*/
static inline void interrupt_controller_hal_set_int_type(int intr, int_type_t type)
{
intr_cntrl_ll_set_int_type(intr, type);
}
/**
* @brief Sets the interrupt level int the interrupt controller.
*
* @param interrupt_number Interrupt number 0 to 31
* @param level priority between 1 (lowest) to 7 (highest)
*/
static inline void interrupt_controller_hal_set_int_level(int intr, int level)
{
intr_cntrl_ll_set_int_level(intr, level);
}
#endif
/**
* @brief Gets the cpu flags given the interrupt number and target cpu.
*
* @param interrupt_number Interrupt number 0 to 31
* @param cpu_number CPU number between 0 and SOC_CPU_CORES_NUM - 1
* @return flags for that interrupt number
*/
static inline uint32_t interrupt_controller_hal_get_cpu_desc_flags(int interrupt_number, int cpu_number)
{
return interrupt_controller_hal_desc_flags(interrupt_number, cpu_number);
}
/**
* @brief enable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be enabled
*/
static inline void interrupt_controller_hal_enable_interrupts(uint32_t mask)
{
intr_cntrl_ll_enable_interrupts(mask);
}
/**
* @brief disable interrupts specified by the mask
*
* @param mask bitmask of interrupts that needs to be disabled
*/
static inline void interrupt_controller_hal_disable_interrupts(uint32_t mask)
{
intr_cntrl_ll_disable_interrupts(mask);
}
/**
* @brief checks if given interrupt number has a valid handler
*
* @param intr interrupt number ranged from 0 to 31
* @param cpu cpu number ranged betweeen 0 to SOC_CPU_CORES_NUM - 1
* @return true for valid handler, false otherwise
*/
static inline bool interrupt_controller_hal_has_handler(int intr, int cpu)
{
return intr_cntrl_ll_has_handler(intr, cpu);
}
/**
* @brief sets interrupt handler and optional argument of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
* @param handler handler invoked when an interrupt occurs
* @param arg optional argument to pass to the handler
*/
static inline void interrupt_controller_hal_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg)
{
intr_cntrl_ll_set_int_handler(intr, handler, arg);
}
/**
* @brief Gets argument passed to handler of a given interrupt number
*
* @param intr interrupt number ranged from 0 to 31
*
* @return argument used by handler of passed interrupt number
*/
static inline void * interrupt_controller_hal_get_int_handler_arg(uint8_t intr)
{
return intr_cntrl_ll_get_int_handler_arg(intr);
}
/**
* @brief Disables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
* @return oldmask where to store old interrupts state
*/
static inline uint32_t interrupt_controller_hal_disable_int_mask(uint32_t newmask)
{
return intr_cntrl_ll_disable_int_mask(newmask);
}
/**
* @brief Enables interrupts that are not located in iram
*
* @param newmask mask of interrupts needs to be disabled
*/
static inline void interrupt_controller_hal_enable_int_mask(uint32_t newmask)
{
intr_cntrl_ll_enable_int_mask(newmask);
}
/**
* @brief Acknowledge an edge-trigger interrupt by clearing its pending flag
*
* @param intr interrupt number ranged from 0 to 31
*/
static inline void interrupt_controller_hal_edge_int_acknowledge(int intr)
{
intr_cntrl_ll_edge_int_acknowledge(intr);
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,46 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "soc/soc_caps.h"
#include "soc/soc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
INTDESC_NORMAL=0,
INTDESC_RESVD,
INTDESC_SPECIAL,
} int_desc_flag_t;
typedef enum {
INTTP_LEVEL=0,
INTTP_EDGE,
INTTP_NA,
} int_type_t;
typedef struct {
int level;
int_type_t type;
int_desc_flag_t cpuflags[SOC_CPU_CORES_NUM];
} int_desc_t;
typedef void (*interrupt_handler_t)(void *arg);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,37 @@
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The HAL is not public api, don't use in application code.
* See readme.md in soc/README.md
******************************************************************************/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/lcd_cam_struct.h"
typedef struct {
lcd_cam_dev_t *dev;
} lcd_hal_context_t;
void lcd_hal_init(lcd_hal_context_t *hal, int id);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,388 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for LEDC.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "hal/ledc_ll.h"
#include "hal/ledc_types.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
ledc_dev_t *dev;
ledc_mode_t speed_mode;
} ledc_hal_context_t;
/**
* @brief Set LEDC low speed timer clock
*
* @param hal Context of the HAL layer
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
#define ledc_hal_set_slow_clk_sel(hal, slow_clk_sel) ledc_ll_set_slow_clk_sel((hal)->dev, slow_clk_sel)
/**
* @brief Get LEDC low speed timer clock
*
* @param hal Context of the HAL layer
* @param slow_clk_sel LEDC low speed timer clock source
*
* @return None
*/
#define ledc_hal_get_slow_clk_sel(hal, slow_clk_sel) ledc_ll_get_slow_clk_sel((hal)->dev, slow_clk_sel)
/**
* @brief Update LEDC low speed timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_ls_timer_update(hal, timer_sel) ledc_ll_ls_timer_update((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Reset LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_rst(hal, timer_sel) ledc_ll_timer_rst((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Pause LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_pause(hal, timer_sel) ledc_ll_timer_pause((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Resume LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_timer_resume(hal, timer_sel) ledc_ll_timer_resume((hal)->dev, (hal)->speed_mode, timer_sel)
/**
* @brief Set LEDC timer clock divider
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
#define ledc_hal_set_clock_divider(hal, timer_sel, clock_divider) ledc_ll_set_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
/**
* @brief Get LEDC timer clock divider
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
*
* @return None
*/
#define ledc_hal_get_clock_divider(hal, timer_sel, clock_divider) ledc_ll_get_clock_divider((hal)->dev, (hal)->speed_mode, timer_sel, clock_divider)
/**
* @brief Set LEDC timer clock source
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Timer clock source
*
* @return None
*/
#define ledc_hal_set_clock_source(hal, timer_sel, clk_src) ledc_ll_set_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
/**
* @brief Get LEDC timer clock source
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_src Pointer to accept the timer clock source
*
* @return None
*/
#define ledc_hal_get_clock_source(hal, timer_sel, clk_src) ledc_ll_get_clock_source((hal)->dev, (hal)->speed_mode, timer_sel, clk_src)
/**
* @brief Set LEDC duty resolution
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
*
* @return None
*/
#define ledc_hal_set_duty_resolution(hal, timer_sel, duty_resolution) ledc_ll_set_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
/**
* @brief Get LEDC duty resolution
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param duty_resolution Pointer to accept the resolution of duty setting in number of bits.
*
* @return None
*/
#define ledc_hal_get_duty_resolution(hal, timer_sel, duty_resolution) ledc_ll_get_duty_resolution((hal)->dev, (hal)->speed_mode, timer_sel, duty_resolution)
/**
* @brief Get LEDC max duty
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param max_duty Pointer to accept the max duty
*
* @return None
*/
#define ledc_hal_get_max_duty(hal, channel_num, max_duty) ledc_ll_get_max_duty((hal)->dev, (hal)->speed_mode, channel_num, max_duty)
/**
* @brief Get LEDC hpoint value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val Pointer to accept the LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
#define ledc_hal_get_hpoint(hal, channel_num, hpoint_val) ledc_ll_get_hpoint((hal)->dev, (hal)->speed_mode, channel_num, hpoint_val)
/**
* @brief Set LEDC the integer part of duty value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val LEDC duty value, the range of duty setting is [0, (2**duty_resolution)]
*
* @return None
*/
#define ledc_hal_set_duty_int_part(hal, channel_num, duty_val) ledc_ll_set_duty_int_part((hal)->dev, (hal)->speed_mode, channel_num, duty_val)
/**
* @brief Set the output enable
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param sig_out_en The output enable status
*
* @return None
*/
#define ledc_hal_set_sig_out_en(hal, channel_num, sig_out_en) ledc_ll_set_sig_out_en((hal)->dev, (hal)->speed_mode, channel_num, sig_out_en)
/**
* @brief Set the duty start
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_start The duty start
*
* @return None
*/
#define ledc_hal_set_duty_start(hal, channel_num, duty_start) ledc_ll_set_duty_start((hal)->dev, (hal)->speed_mode, channel_num, duty_start)
/**
* @brief Set output idle level
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param idle_level The output idle level
*
* @return None
*/
#define ledc_hal_set_idle_level(hal, channel_num, idle_level) ledc_ll_set_idle_level((hal)->dev, (hal)->speed_mode, channel_num, idle_level)
/**
* @brief Set fade end interrupt enable
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param fade_end_intr_en The fade end interrupt enable status
*
* @return None
*/
#define ledc_hal_set_fade_end_intr(hal, channel_num, fade_end_intr_en) ledc_ll_set_fade_end_intr((hal)->dev, (hal)->speed_mode, channel_num, fade_end_intr_en)
/**
* @brief Set timer index of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return None
*/
#define ledc_hal_bind_channel_timer(hal, channel_num, timer_sel) ledc_ll_bind_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
/**
* @brief Get timer index of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel Pointer to accept the LEDC timer index
*
* @return None
*/
#define ledc_hal_get_channel_timer(hal, channel_num, timer_sel) ledc_ll_get_channel_timer((hal)->dev, (hal)->speed_mode, channel_num, timer_sel)
/**
* @brief Init the LEDC hal. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param speed_mode speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mod
*
* @return None
*/
void ledc_hal_init(ledc_hal_context_t *hal, ledc_mode_t speed_mode);
/**
* @brief Update channel configure when select low speed mode
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
void ledc_hal_ls_channel_update(ledc_hal_context_t *hal, ledc_channel_t channel_num);
/**
* @brief Set LEDC hpoint value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param hpoint_val LEDC hpoint value(max: 0xfffff)
*
* @return None
*/
void ledc_hal_set_hpoint(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t hpoint_val);
/**
* @brief Get LEDC duty value
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_val Pointer to accept the LEDC duty value
*
* @return None
*/
void ledc_hal_get_duty(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t *duty_val);
/**
* @brief Set LEDC duty change direction
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_direction LEDC duty change direction, increase or decrease
*
* @return None
*/
void ledc_hal_set_duty_direction(ledc_hal_context_t *hal, ledc_channel_t channel_num, ledc_duty_direction_t duty_direction);
/**
* @brief Set the number of increased or decreased times
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_num The number of increased or decreased times
*
* @return None
*/
void ledc_hal_set_duty_num(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_num);
/**
* @brief Set the duty cycles of increase or decrease
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_cycle The duty cycles
*
* @return None
*/
void ledc_hal_set_duty_cycle(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_cycle);
/**
* @brief Set the step scale of increase or decrease
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param duty_scale The step scale
*
* @return None
*/
void ledc_hal_set_duty_scale(ledc_hal_context_t *hal, ledc_channel_t channel_num, uint32_t duty_scale);
/**
* @brief Get interrupt status of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
* @param intr_status Pointer to accept the interrupt status
*
* @return None
*/
void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_status);
/**
* @brief Clear interrupt status of the specified channel
*
* @param hal Context of the HAL layer
* @param channel_num LEDC channel index (0-7), select from ledc_channel_t
*
* @return None
*/
void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num);
/**
* @brief Get clock config of LEDC timer
*
* @param hal Context of the HAL layer
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
* @param clk_cfg Pointer to accept clock config
*
* @return None
*/
void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg);
/**
* @brief Config low speed timer clock source with clock config
*s
* @param hal Context of the HAL layer
* @param clk_cfg clock config
*
* @return None
*/
void ledc_hal_set_slow_clk(ledc_hal_context_t *hal, ledc_clk_cfg_t clk_cfg);

View File

@@ -0,0 +1,157 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
typedef enum {
#if SOC_LEDC_SUPPORT_HS_MODE
LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */
#endif
LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */
LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */
} ledc_mode_t;
typedef enum {
LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */
LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */
LEDC_INTR_MAX,
} ledc_intr_type_t;
typedef enum {
LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */
LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */
LEDC_DUTY_DIR_MAX,
} ledc_duty_direction_t;
typedef enum {
LEDC_SLOW_CLK_RTC8M = 0, /*!< LEDC low speed timer clock source is 8MHz RTC clock*/
LEDC_SLOW_CLK_APB, /*!< LEDC low speed timer clock source is 80MHz APB clock*/
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
LEDC_SLOW_CLK_XTAL, /*!< LEDC low speed timer clock source XTAL clock*/
#endif
} ledc_slow_clk_sel_t;
typedef enum {
LEDC_AUTO_CLK = 0, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/
LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/
LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/
LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/
#if SOC_LEDC_SUPPORT_XTAL_CLOCK
LEDC_USE_XTAL_CLK, /*!< LEDC timer select XTAL clock as source clock*/
#endif
} ledc_clk_cfg_t;
/* Note: Setting numeric values to match ledc_clk_cfg_t values are a hack to avoid collision with
LEDC_AUTO_CLK in the driver, as these enums have very similar names and user may pass
one of these by mistake. */
typedef enum {
LEDC_REF_TICK = LEDC_USE_REF_TICK, /*!< LEDC timer clock divided from reference tick (1Mhz) */
LEDC_APB_CLK = LEDC_USE_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */
} ledc_clk_src_t;
typedef enum {
LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */
LEDC_TIMER_1, /*!< LEDC timer 1 */
LEDC_TIMER_2, /*!< LEDC timer 2 */
LEDC_TIMER_3, /*!< LEDC timer 3 */
LEDC_TIMER_MAX,
} ledc_timer_t;
typedef enum {
LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */
LEDC_CHANNEL_1, /*!< LEDC channel 1 */
LEDC_CHANNEL_2, /*!< LEDC channel 2 */
LEDC_CHANNEL_3, /*!< LEDC channel 3 */
LEDC_CHANNEL_4, /*!< LEDC channel 4 */
LEDC_CHANNEL_5, /*!< LEDC channel 5 */
#if SOC_LEDC_CHANNEL_NUM > 6
LEDC_CHANNEL_6, /*!< LEDC channel 6 */
LEDC_CHANNEL_7, /*!< LEDC channel 7 */
#endif
LEDC_CHANNEL_MAX,
} ledc_channel_t;
typedef enum {
LEDC_TIMER_1_BIT = 1, /*!< LEDC PWM duty resolution of 1 bits */
LEDC_TIMER_2_BIT, /*!< LEDC PWM duty resolution of 2 bits */
LEDC_TIMER_3_BIT, /*!< LEDC PWM duty resolution of 3 bits */
LEDC_TIMER_4_BIT, /*!< LEDC PWM duty resolution of 4 bits */
LEDC_TIMER_5_BIT, /*!< LEDC PWM duty resolution of 5 bits */
LEDC_TIMER_6_BIT, /*!< LEDC PWM duty resolution of 6 bits */
LEDC_TIMER_7_BIT, /*!< LEDC PWM duty resolution of 7 bits */
LEDC_TIMER_8_BIT, /*!< LEDC PWM duty resolution of 8 bits */
LEDC_TIMER_9_BIT, /*!< LEDC PWM duty resolution of 9 bits */
LEDC_TIMER_10_BIT, /*!< LEDC PWM duty resolution of 10 bits */
LEDC_TIMER_11_BIT, /*!< LEDC PWM duty resolution of 11 bits */
LEDC_TIMER_12_BIT, /*!< LEDC PWM duty resolution of 12 bits */
LEDC_TIMER_13_BIT, /*!< LEDC PWM duty resolution of 13 bits */
LEDC_TIMER_14_BIT, /*!< LEDC PWM duty resolution of 14 bits */
#if SOC_LEDC_TIMER_BIT_WIDE_NUM > 14
LEDC_TIMER_15_BIT, /*!< LEDC PWM duty resolution of 15 bits */
LEDC_TIMER_16_BIT, /*!< LEDC PWM duty resolution of 16 bits */
LEDC_TIMER_17_BIT, /*!< LEDC PWM duty resolution of 17 bits */
LEDC_TIMER_18_BIT, /*!< LEDC PWM duty resolution of 18 bits */
LEDC_TIMER_19_BIT, /*!< LEDC PWM duty resolution of 19 bits */
LEDC_TIMER_20_BIT, /*!< LEDC PWM duty resolution of 20 bits */
#endif
LEDC_TIMER_BIT_MAX,
} ledc_timer_bit_t;
typedef enum {
LEDC_FADE_NO_WAIT = 0, /*!< LEDC fade function will return immediately */
LEDC_FADE_WAIT_DONE, /*!< LEDC fade function will block until fading to the target duty */
LEDC_FADE_MAX,
} ledc_fade_mode_t;
/**
* @brief Configuration parameters of LEDC channel for ledc_channel_config function
*/
typedef struct {
int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16 */
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
ledc_channel_t channel; /*!< LEDC channel (0 - 7) */
ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable */
ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - 3) */
uint32_t duty; /*!< LEDC channel duty, the range of duty setting is [0, (2**duty_resolution)] */
int hpoint; /*!< LEDC channel hpoint value, the max value is 0xfffff */
} ledc_channel_config_t;
/**
* @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
*/
typedef struct {
ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode */
union {
ledc_timer_bit_t duty_resolution; /*!< LEDC channel duty resolution */
ledc_timer_bit_t bit_num __attribute__((deprecated)); /*!< Deprecated in ESP-IDF 3.0. This is an alias to 'duty_resolution' for backward compatibility with ESP-IDF 2.1 */
};
ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */
uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */
ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock.
For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK.
For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/
} ledc_timer_config_t;
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -0,0 +1,87 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/// Interrupts for MCPWM
typedef enum {
MCPWM_LL_INTR_CAP0 = BIT(27), ///< Capture 0 happened
MCPWM_LL_INTR_CAP1 = BIT(28), ///< Capture 1 happened
MCPWM_LL_INTR_CAP2 = BIT(29), ///< Capture 2 happened
} mcpwm_intr_t;
/**
* @brief Select type of MCPWM counter
*/
typedef enum {
MCPWM_UP_COUNTER = 1, /*!<For asymmetric MCPWM*/
MCPWM_DOWN_COUNTER, /*!<For asymmetric MCPWM*/
MCPWM_UP_DOWN_COUNTER, /*!<For symmetric MCPWM, frequency is half of MCPWM frequency set*/
MCPWM_COUNTER_MAX, /*!<Maximum counter mode*/
} mcpwm_counter_type_t;
/**
* @brief Select type of MCPWM duty cycle mode
*/
typedef enum {
MCPWM_DUTY_MODE_0 = 0, /*!<Active high duty, i.e. duty cycle proportional to high time for asymmetric MCPWM*/
MCPWM_DUTY_MODE_1, /*!<Active low duty, i.e. duty cycle proportional to low time for asymmetric MCPWM, out of phase(inverted) MCPWM*/
MCPWM_HAL_GENERATOR_MODE_FORCE_LOW,
MCPWM_HAL_GENERATOR_MODE_FORCE_HIGH,
MCPWM_DUTY_MODE_MAX, /*!<Num of duty cycle modes*/
} mcpwm_duty_type_t;
/**
* @brief MCPWM select action to be taken on the output when event happens
*/
typedef enum {
MCPWM_ACTION_NO_CHANGE = 0, /*!<No change in the output*/
MCPWM_ACTION_FORCE_LOW, /*!<Make output low*/
MCPWM_ACTION_FORCE_HIGH, /*!<Make output high*/
MCPWM_ACTION_TOGGLE, /*!<Make output toggle*/
} mcpwm_output_action_t;
/**
* @brief MCPWM deadtime types, used to generate deadtime, RED refers to rising edge delay and FED refers to falling edge delay
*/
typedef enum {
MCPWM_DEADTIME_BYPASS = 0, /*!<Bypass the deadtime*/
MCPWM_BYPASS_RED, /*!<MCPWMXA = no change, MCPWMXB = falling edge delay*/
MCPWM_BYPASS_FED, /*!<MCPWMXA = rising edge delay, MCPWMXB = no change*/
MCPWM_ACTIVE_HIGH_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = falling edge delay*/
MCPWM_ACTIVE_LOW_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = compliment of falling edge delay*/
MCPWM_ACTIVE_HIGH_COMPLIMENT_MODE, /*!<MCPWMXA = rising edge delay, MCPWMXB = compliment of falling edge delay*/
MCPWM_ACTIVE_LOW_COMPLIMENT_MODE, /*!<MCPWMXA = compliment of rising edge delay, MCPWMXB = falling edge delay*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXA, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXA*/
MCPWM_ACTIVE_RED_FED_FROM_PWMXB, /*!<MCPWMXA = MCPWMXB = rising edge delay as well as falling edge delay, generated from MCPWMXB*/
MCPWM_DEADTIME_TYPE_MAX,
} mcpwm_deadtime_type_t;
/**
* @brief MCPWM select sync signal input
*/
typedef enum {
MCPWM_SELECT_SYNC0 = 4, /*!<Select SYNC0 as input*/
MCPWM_SELECT_SYNC1, /*!<Select SYNC1 as input*/
MCPWM_SELECT_SYNC2, /*!<Select SYNC2 as input*/
} mcpwm_sync_signal_t;
/**
* @brief MCPWM select capture starts from which edge
*/
typedef enum {
MCPWM_NEG_EDGE = BIT(0), /*!<Capture the negative edge*/
MCPWM_POS_EDGE = BIT(1), /*!<Capture the positive edge*/
MCPWM_BOTH_EDGE = BIT(1)|BIT(0), /*!<Capture both edges*/
} mcpwm_capture_on_edge_t;

View File

@@ -0,0 +1,36 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include "esp_err.h"
#include "hal/mpu_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Specify the type of access allowed on a memory region.
*
* @param id index to the region table; on targets not SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED,
* the region divisions is predefined in hardware which is likely reflected in LL implementation.
* @param access type of access allowed
*/
void mpu_hal_set_region_access(int id, mpu_access_t access);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,34 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include "soc/soc_caps.h"
#if SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED
typedef void** mpu_region_table_t;
#endif
typedef enum {
MPU_REGION_ILLEGAL,
#if SOC_MPU_REGION_RO_SUPPORTED
MPU_REGION_RO, // read-only
#endif
#if SOC_MPU_REGION_WO_SUPPORTED
MPU_REGION_WO, // write-only
#endif
MPU_REGION_RW, // read-write
MPU_REGION_X, // executable
MPU_REGION_RWX // read-write-executable
} mpu_access_t;

View File

@@ -0,0 +1,223 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for PCNT.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include <stdio.h>
#include "soc/pcnt_periph.h"
#include "hal/pcnt_types.h"
#include "hal/pcnt_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
pcnt_dev_t *dev;
} pcnt_hal_context_t;
/**
* @brief Set PCNT counter mode
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pos_mode Counter mode when detecting positive edge
* @param neg_mode Counter mode when detecting negative edge
* @param hctrl_mode Counter mode when control signal is high level
* @param lctrl_mode Counter mode when control signal is low level
*/
#define pcnt_hal_set_mode(hal, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode) pcnt_ll_set_mode((hal)->dev, unit, channel, pos_mode, neg_mode, hctrl_mode, lctrl_mode)
/**
* @brief Get pulse counter value
*
* @param hal Context of the HAL layer
* @param unit Pulse Counter unit number
* @param count Pointer to accept counter value
*/
#define pcnt_hal_get_counter_value(hal, unit, count) pcnt_ll_get_counter_value((hal)->dev, unit, count)
/**
* @brief Pause PCNT counter of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_counter_pause(hal, unit) pcnt_ll_counter_pause((hal)->dev, unit)
/**
* @brief Resume counting for PCNT counter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number, select from unit_t
*/
#define pcnt_hal_counter_resume(hal, unit) pcnt_ll_counter_resume((hal)->dev, unit)
/**
* @brief Clear and reset PCNT counter value to zero
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number, select from unit_t
*/
#define pcnt_hal_counter_clear(hal, unit) pcnt_ll_counter_clear((hal)->dev, unit)
/**
* @brief Enable PCNT interrupt for PCNT unit
* @note
* Each Pulse counter unit has five watch point events that share the same interrupt.
* Configure events with pcnt_event_enable() and pcnt_event_disable()
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_intr_enable(hal, unit) pcnt_ll_intr_enable((hal)->dev, unit)
/**
* @brief Disable PCNT interrupt for PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_intr_disable(hal, unit) pcnt_ll_intr_disable((hal)->dev, unit)
/**
* @brief Get PCNT interrupt status
*
* @param hal Context of the HAL layer
* @param mask The interrupt status mask to be cleared. Pointer to accept value interrupt status mask.
*/
#define pcnt_hal_get_intr_status(hal, mask) pcnt_ll_get_intr_status((hal)->dev, mask)
/**
* @brief Clear PCNT interrupt status
*
* @param hal Context of the HAL layer
* @param mask The interrupt status mask to be cleared.
*/
#define pcnt_hal_clear_intr_status(hal, mask) pcnt_ll_clear_intr_status((hal)->dev, mask)
/**
* @brief Enable PCNT event of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*/
#define pcnt_hal_event_enable(hal, unit, evt_type) pcnt_ll_event_enable((hal)->dev, unit, evt_type)
/**
* @brief Disable PCNT event of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*/
#define pcnt_hal_event_disable(hal, unit, evt_type) pcnt_ll_event_disable((hal)->dev, unit, evt_type)
/**
* @brief Set PCNT event value of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
*
* @param value Counter value for PCNT event
*/
#define pcnt_hal_set_event_value(hal, unit, evt_type, value) pcnt_ll_set_event_value((hal)->dev, unit, evt_type, value)
/**
* @brief Get PCNT event value of PCNT unit
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param evt_type Watch point event type.
* All enabled events share the same interrupt (one interrupt per pulse counter unit).
* @param value Pointer to accept counter value for PCNT event
*/
#define pcnt_hal_get_event_value(hal, unit, evt_type, value) pcnt_ll_get_event_value((hal)->dev, unit, evt_type, value)
/**
* @brief Get PCNT event status
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @return event status word
*/
#define pcnt_hal_get_event_status(hal, unit) pcnt_ll_get_event_status((hal)->dev, unit)
/**
* @brief Set PCNT filter value
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param filter_val PCNT signal filter value, counter in APB_CLK cycles.
* Any pulses lasting shorter than this will be ignored when the filter is enabled.
* @note
* filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
*/
#define pcnt_hal_set_filter_value(hal, unit, filter_val) pcnt_ll_set_filter_value((hal)->dev, unit, filter_val)
/**
* @brief Get PCNT filter value
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
* @param filter_val Pointer to accept PCNT filter value.
*/
#define pcnt_hal_get_filter_value(hal, unit, filter_val) pcnt_ll_get_filter_value((hal)->dev, unit, filter_val)
/**
* @brief Enable PCNT input filter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_filter_enable(hal, unit) pcnt_ll_filter_enable((hal)->dev, unit)
/**
* @brief Disable PCNT input filter
*
* @param hal Context of the HAL layer
* @param unit PCNT unit number
*/
#define pcnt_hal_filter_disable(hal, unit) pcnt_ll_filter_disable((hal)->dev, unit)
/**
* @brief Init the PCNT hal and set the PCNT to the default configuration. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param pcnt_num The uart port number, the max port number is (PCNT_NUM_MAX -1)
*/
void pcnt_hal_init(pcnt_hal_context_t *hal, int pcnt_num);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,111 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#define PCNT_PIN_NOT_USED (-1) /*!< When selected for a pin, this pin will not be used */
/**
* @brief PCNT port number, the max port number is (PCNT_PORT_MAX - 1).
*/
typedef enum {
PCNT_PORT_0 = 0, /*!< PCNT port 0 */
PCNT_PORT_MAX, /*!< PCNT port max */
} pcnt_port_t;
/**
* @brief Selection of all available PCNT units
*/
typedef enum {
PCNT_UNIT_0 = 0, /*!< PCNT unit 0 */
PCNT_UNIT_1 = 1, /*!< PCNT unit 1 */
PCNT_UNIT_2 = 2, /*!< PCNT unit 2 */
PCNT_UNIT_3 = 3, /*!< PCNT unit 3 */
#if SOC_PCNT_UNIT_NUM > 4
PCNT_UNIT_4 = 4, /*!< PCNT unit 4 */
PCNT_UNIT_5 = 5, /*!< PCNT unit 5 */
PCNT_UNIT_6 = 6, /*!< PCNT unit 6 */
PCNT_UNIT_7 = 7, /*!< PCNT unit 7 */
#endif
PCNT_UNIT_MAX,
} pcnt_unit_t;
/**
* @brief Selection of available modes that determine the counter's action depending on the state of the control signal's input GPIO
* @note Configuration covers two actions, one for high, and one for low level on the control input
*/
typedef enum {
PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase) */
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition) */
PCNT_MODE_MAX
} pcnt_ctrl_mode_t;
/**
* @brief Selection of available modes that determine the counter's action on the edge of the pulse signal's input GPIO
* @note Configuration covers two actions, one for positive, and one for negative edge on the pulse input
*/
typedef enum {
PCNT_COUNT_DIS = 0, /*!< Counter mode: Inhibit counter(counter value will not change in this condition) */
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value */
PCNT_COUNT_DEC = 2, /*!< Counter mode: Decrease counter value */
PCNT_COUNT_MAX
} pcnt_count_mode_t;
/**
* @brief Selection of channels available for a single PCNT unit
*/
typedef enum {
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel 0 */
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel 1 */
PCNT_CHANNEL_MAX,
} pcnt_channel_t;
/**
* @brief Selection of counter's events the may trigger an interrupt
*/
typedef enum {
PCNT_EVT_THRES_1 = BIT(2), /*!< PCNT watch point event: threshold1 value event */
PCNT_EVT_THRES_0 = BIT(3), /*!< PCNT watch point event: threshold0 value event */
PCNT_EVT_L_LIM = BIT(4), /*!< PCNT watch point event: Minimum counter value */
PCNT_EVT_H_LIM = BIT(5), /*!< PCNT watch point event: Maximum counter value */
PCNT_EVT_ZERO = BIT(6), /*!< PCNT watch point event: counter value zero event */
PCNT_EVT_MAX
} pcnt_evt_type_t;
/**
* @brief Pulse Counter configuration for a single channel
*/
typedef struct {
int pulse_gpio_num; /*!< Pulse input GPIO number, if you want to use GPIO16, enter pulse_gpio_num = 16, a negative value will be ignored */
int ctrl_gpio_num; /*!< Control signal input GPIO number, a negative value will be ignored */
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode */
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode */
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode */
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode */
int16_t counter_h_lim; /*!< Maximum counter value */
int16_t counter_l_lim; /*!< Minimum counter value */
pcnt_unit_t unit; /*!< PCNT unit number */
pcnt_channel_t channel; /*!< the PCNT channel */
} pcnt_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,112 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "soc/soc_caps.h"
#include "soc/rmt_struct.h"
/**
* @brief HAL context type of RMT driver
*
*/
typedef struct {
rmt_dev_t *regs; /*!< RMT Register base address */
rmt_mem_t *mem; /*!< RMT Memory base address */
} rmt_hal_context_t;
#define RMT_MEM_OWNER_SW (0) /*!< RMT Memory ownership belongs to software side */
#define RMT_MEM_OWNER_HW (1) /*!< RMT Memory ownership belongs to hardware side */
/**
* @brief Initialize the RMT HAL driver
*
* @param hal: RMT HAL context
*/
void rmt_hal_init(rmt_hal_context_t *hal);
/**
* @brief Reset RMT TX Channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
*/
void rmt_hal_tx_channel_reset(rmt_hal_context_t *hal, uint32_t channel);
/**
* @brief Reset RMT TX Channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
*/
void rmt_hal_rx_channel_reset(rmt_hal_context_t *hal, uint32_t channel);
/**
* @brief Set counter clock for RMT channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param base_clk_hz: base clock for RMT internal channel (counter clock will divide from it)
* @param counter_clk_hz: target counter clock
*/
void rmt_hal_tx_set_channel_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t counter_clk_hz);
/**
* @brief Set carrier clock for RMT channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param base_clk_hz: base clock for RMT carrier generation (carrier clock will divide from it)
* @param carrier_clk_hz: target carrier clock
* @param carrier_clk_duty: duty ratio of carrier clock
*/
void rmt_hal_set_carrier_clock(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t carrier_clk_hz, float carrier_clk_duty);
/**
* @brief Set filter threshold for RMT Receive channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param base_clk_hz: base clock for RMT receive filter
* @param thres_us: threshold of RMT receive filter, in us
*/
void rmt_hal_set_rx_filter_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us);
/**
* @brief Set idle threshold for RMT Receive channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param base_clk_hz: base clock for RMT receive channel
* @param thres_us: IDLE threshold for RMT receive channel
*/
void rmt_hal_set_rx_idle_thres(rmt_hal_context_t *hal, uint32_t channel, uint32_t base_clk_hz, uint32_t thres_us);
/**
* @brief Receive a frame from RMT channel
*
* @param hal: RMT HAL context
* @param channel: RMT channel number
* @param buf: buffer to store received RMT frame
* @return number of items that get received
*/
uint32_t rmt_hal_receive(rmt_hal_context_t *hal, uint32_t channel, rmt_item32_t *buf);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,127 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
/**
* @brief RMT channel ID
*
*/
typedef enum {
RMT_CHANNEL_0, /*!< RMT channel number 0 */
RMT_CHANNEL_1, /*!< RMT channel number 1 */
RMT_CHANNEL_2, /*!< RMT channel number 2 */
RMT_CHANNEL_3, /*!< RMT channel number 3 */
#if SOC_RMT_CHANNELS_PER_GROUP > 4
RMT_CHANNEL_4, /*!< RMT channel number 4 */
RMT_CHANNEL_5, /*!< RMT channel number 5 */
RMT_CHANNEL_6, /*!< RMT channel number 6 */
RMT_CHANNEL_7, /*!< RMT channel number 7 */
#endif
RMT_CHANNEL_MAX /*!< Number of RMT channels */
} rmt_channel_t;
/**
* @brief RMT Internal Memory Owner
*
*/
typedef enum {
RMT_MEM_OWNER_TX, /*!< RMT RX mode, RMT transmitter owns the memory block*/
RMT_MEM_OWNER_RX, /*!< RMT RX mode, RMT receiver owns the memory block*/
RMT_MEM_OWNER_MAX,
} rmt_mem_owner_t;
/**
* @brief Clock Source of RMT Channel
*
*/
typedef enum {
#if SOC_RMT_SUPPORT_REF_TICK
RMT_BASECLK_REF = 0, /*!< RMT source clock is REF_TICK, 1MHz by default */
#endif
RMT_BASECLK_APB = 1, /*!< RMT source clock is APB CLK, 80Mhz by default */
#if SOC_RMT_SUPPORT_XTAL
RMT_BASECLK_XTAL = 3, /*!< RMT source clock is XTAL clock, 40Mhz by default */
#endif
RMT_BASECLK_MAX,
} rmt_source_clk_t;
/**
* @brief RMT Data Mode
*
* @note We highly recommended to use MEM mode not FIFO mode since there will be some gotcha in FIFO mode.
*
*/
typedef enum {
RMT_DATA_MODE_FIFO, /*<! RMT memory access in FIFO mode */
RMT_DATA_MODE_MEM, /*<! RMT memory access in memory mode */
RMT_DATA_MODE_MAX,
} rmt_data_mode_t;
/**
* @brief RMT Channel Working Mode (TX or RX)
*
*/
typedef enum {
RMT_MODE_TX, /*!< RMT TX mode */
RMT_MODE_RX, /*!< RMT RX mode */
RMT_MODE_MAX
} rmt_mode_t;
/**
* @brief RMT Idle Level
*
*/
typedef enum {
RMT_IDLE_LEVEL_LOW, /*!< RMT TX idle level: low Level */
RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */
RMT_IDLE_LEVEL_MAX,
} rmt_idle_level_t;
/**
* @brief RMT Carrier Level
*
*/
typedef enum {
RMT_CARRIER_LEVEL_LOW, /*!< RMT carrier wave is modulated for low Level output */
RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */
RMT_CARRIER_LEVEL_MAX
} rmt_carrier_level_t;
/**
* @brief RMT Channel Status
*
*/
typedef enum {
RMT_CHANNEL_UNINIT, /*!< RMT channel uninitialized */
RMT_CHANNEL_IDLE, /*!< RMT channel status idle */
RMT_CHANNEL_BUSY, /*!< RMT channel status busy */
} rmt_channel_status_t;
/**
* @brief Data struct of RMT channel status
*/
typedef struct {
rmt_channel_status_t status[RMT_CHANNEL_MAX]; /*!< Store the current status of each channel */
} rmt_channel_status_result_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,56 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "hal/gpio_types.h"
#include "hal/rtc_cntl_ll.h"
#if !CONFIG_IDF_TARGET_ESP32C3
#include "hal/rtc_io_ll.h"
#endif
#define RTC_HAL_DMA_LINK_NODE_SIZE (16)
#if SOC_PM_SUPPORT_EXT_WAKEUP
#define rtc_hal_ext1_get_wakeup_pins() rtc_cntl_ll_ext1_get_wakeup_pins()
#define rtc_hal_ext1_set_wakeup_pins(mask, mode) rtc_cntl_ll_ext1_set_wakeup_pins(mask, mode)
#define rtc_hal_ext1_clear_wakeup_pins() rtc_cntl_ll_ext1_clear_wakeup_pins()
#endif
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#define rtc_hal_gpio_get_wakeup_pins() rtc_cntl_ll_gpio_get_wakeup_pins()
#define rtc_hal_gpio_clear_wakeup_pins() rtc_cntl_ll_gpio_clear_wakeup_pins()
#define rtc_hal_gpio_set_wakeup_pins() rtc_cntl_ll_gpio_set_wakeup_pins()
#endif
#define rtc_hal_set_wakeup_timer(ticks) rtc_cntl_ll_set_wakeup_timer(ticks)
void * rtc_cntl_hal_dma_link_init(void *elem, void *buff, int size, void *next);
void rtc_cntl_hal_enable_cpu_retention(void *addr);
#define rtc_cntl_hal_disable_cpu_retention() rtc_cntl_ll_disable_cpu_retention()
/*
* Enable wakeup from ULP coprocessor.
*/
#define rtc_hal_ulp_wakeup_enable() rtc_cntl_ll_ulp_wakeup_enable()

View File

@@ -0,0 +1,264 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for RTC IO master (common part)
#pragma once
#include <esp_err.h>
#if !CONFIG_IDF_TARGET_ESP32C3
#include "soc/soc_caps.h"
#include "hal/rtc_io_ll.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
/**
* Select the rtcio function.
*
* @note The RTC function must be selected before the pad analog function is enabled.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param func Select pin function.
*/
#define rtcio_hal_function_select(rtcio_num, func) rtcio_ll_function_select(rtcio_num, func)
/**
* Enable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_output_enable(rtcio_num) rtcio_ll_output_enable(rtcio_num)
/**
* Disable rtcio output.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_output_disable(rtcio_num) rtcio_ll_output_disable(rtcio_num)
/**
* Set RTCIO output level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level 0: output low; ~0: output high.
*/
#define rtcio_hal_set_level(rtcio_num, level) rtcio_ll_set_level(rtcio_num, level)
/**
* Enable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_input_enable(rtcio_num) rtcio_ll_input_enable(rtcio_num)
/**
* Disable rtcio input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_input_disable(rtcio_num) rtcio_ll_input_disable(rtcio_num)
/**
* Get RTCIO input level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return 0: input low; ~0: input high.
*/
#define rtcio_hal_get_level(rtcio_num) rtcio_ll_get_level(rtcio_num)
/**
* @brief Set RTC GPIO pad drive capability.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param strength Drive capability of the pad. Range: 0 ~ 3.
*/
#define rtcio_hal_set_drive_capability(rtcio_num, strength) rtcio_ll_set_drive_capability(rtcio_num, strength)
/**
* @brief Get RTC GPIO pad drive capability.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return Drive capability of the pad. Range: 0 ~ 3.
*/
#define rtcio_hal_get_drive_capability(rtcio_num) rtcio_ll_get_drive_capability(rtcio_num)
/**
* Set RTCIO output level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level 0: output low; ~0: output high.
*/
#define rtcio_hal_set_level(rtcio_num, level) rtcio_ll_set_level(rtcio_num, level)
/**
* Get RTCIO input level.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @return 0: input low; ~0: input high.
*/
#define rtcio_hal_get_level(rtcio_num) rtcio_ll_get_level(rtcio_num)
/**
* Set RTC IO direction.
*
* Configure RTC IO direction, such as output only, input only,
* output and input.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param mode IO direction.
*/
void rtcio_hal_set_direction(int rtcio_num, rtc_gpio_mode_t mode);
/**
* Set RTC IO direction in deep sleep or disable sleep status.
*
* NOTE: ESP32 support INPUT_ONLY mode.
* ESP32S2 support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param mode IO direction.
*/
void rtcio_hal_set_direction_in_sleep(int rtcio_num, rtc_gpio_mode_t mode);
/**
* RTC GPIO pullup enable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pullup_enable(rtcio_num) rtcio_ll_pullup_enable(rtcio_num)
/**
* RTC GPIO pullup disable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pullup_disable(rtcio_num) rtcio_ll_pullup_disable(rtcio_num)
/**
* RTC GPIO pulldown enable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pulldown_enable(rtcio_num) rtcio_ll_pulldown_enable(rtcio_num)
/**
* RTC GPIO pulldown disable.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_pulldown_disable(rtcio_num) rtcio_ll_pulldown_disable(rtcio_num)
#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
#if SOC_RTCIO_HOLD_SUPPORTED
/**
* Enable force hold function for RTC IO pad.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_enable(rtcio_num) rtcio_ll_force_hold_enable(rtcio_num)
/**
* Disable hold function on an RTC IO pad
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_disable(rtcio_num) rtcio_ll_force_hold_disable(rtcio_num)
/**
* Enable force hold function for RTC IO pads.
*
* Enabling HOLD function will cause the pad to lock current status, such as,
* input/output enable, input/output value, function, drive strength values.
* This function is useful when going into light or deep sleep mode to prevent
* the pin configuration from changing.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_hold_all() rtcio_ll_force_hold_all()
/**
* Disable hold function on an RTC IO pads.
*
* @note If disable the pad hold, the status of pad maybe changed in sleep mode.
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_unhold_all() rtcio_ll_force_unhold_all()
#endif // SOC_RTCIO_HOLD_SUPPORTED
#if SOC_RTCIO_WAKE_SUPPORTED
/**
* Enable wakeup function and set wakeup type from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param type Wakeup on high level or low level.
*/
#define rtcio_hal_wakeup_enable(rtcio_num, type) rtcio_ll_wakeup_enable(rtcio_num, type)
/**
* Disable wakeup function from light sleep status for rtcio.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
#define rtcio_hal_wakeup_disable(rtcio_num) rtcio_ll_wakeup_disable(rtcio_num)
/**
* Set specific logic level on an RTC IO pin as a wakeup trigger.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
* @param level Logic level (0)
*/
#define rtcio_hal_ext0_set_wakeup_pin(rtcio_num, level) rtcio_ll_ext0_set_wakeup_pin(rtcio_num, level)
#endif
#if SOC_RTCIO_HOLD_SUPPORTED || SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
/**
* Helper function to disconnect internal circuits from an RTC IO
* This function disables input, output, pullup, pulldown, and enables
* hold feature for an RTC IO.
* Use this function if an RTC IO needs to be disconnected from internal
* circuits in deep sleep, to minimize leakage current.
*
* In particular, for ESP32-WROVER module, call
* rtc_gpio_isolate(GPIO_NUM_12) before entering deep sleep, to reduce
* deep sleep current.
*
* @param rtcio_num The index of rtcio. 0 ~ SOC_RTCIO_PIN_COUNT.
*/
void rtcio_hal_isolate(int rtc_num);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,25 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/** RTCIO output/input mode type. */
typedef enum {
RTC_GPIO_MODE_INPUT_ONLY , /*!< Pad input */
RTC_GPIO_MODE_OUTPUT_ONLY, /*!< Pad output */
RTC_GPIO_MODE_INPUT_OUTPUT, /*!< Pad input + output */
RTC_GPIO_MODE_DISABLED, /*!< Pad (output + input) disable */
RTC_GPIO_MODE_OUTPUT_OD, /*!< Pad open-drain output */
RTC_GPIO_MODE_INPUT_OUTPUT_OD, /*!< Pad input + open-drain output */
} rtc_gpio_mode_t;

View File

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

View File

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

View File

@@ -0,0 +1,47 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "soc/soc.h"
/// Mask of interrupts sending to the host.
typedef enum {
SDIO_SLAVE_HOSTINT_BIT0 = BIT(0), ///< General purpose interrupt bit 0.
SDIO_SLAVE_HOSTINT_BIT1 = BIT(1),
SDIO_SLAVE_HOSTINT_BIT2 = BIT(2),
SDIO_SLAVE_HOSTINT_BIT3 = BIT(3),
SDIO_SLAVE_HOSTINT_BIT4 = BIT(4),
SDIO_SLAVE_HOSTINT_BIT5 = BIT(5),
SDIO_SLAVE_HOSTINT_BIT6 = BIT(6),
SDIO_SLAVE_HOSTINT_BIT7 = BIT(7),
SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET = BIT(23), ///< New packet available
} sdio_slave_hostint_t;
/// Timing of SDIO slave
typedef enum {
SDIO_SLAVE_TIMING_PSEND_PSAMPLE = 0,/**< Send at posedge, and sample at posedge. Default value for HS mode.
* Normally there's no problem using this to work in DS mode.
*/
SDIO_SLAVE_TIMING_NSEND_PSAMPLE ,///< Send at negedge, and sample at posedge. Default value for DS mode and below.
SDIO_SLAVE_TIMING_PSEND_NSAMPLE, ///< Send at posedge, and sample at negedge
SDIO_SLAVE_TIMING_NSEND_NSAMPLE, ///< Send at negedge, and sample at negedge
} sdio_slave_timing_t;
/// Configuration of SDIO slave mode
typedef enum {
SDIO_SLAVE_SEND_STREAM = 0, ///< Stream mode, all packets to send will be combined as one if possible
SDIO_SLAVE_SEND_PACKET = 1, ///< Packet mode, one packets will be sent one after another (only increase packet_len if last packet sent).
} sdio_slave_sending_mode_t;

View File

@@ -0,0 +1,90 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in soc/include/hal/readme.md
******************************************************************************/
#pragma once
#include <stddef.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "soc/lldesc.h"
#include "hal/sha_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Hashes a single message block
*
* @param sha_type SHA algorithm to hash with
* @param data_block Input message to be hashed
* @param block_word_len Length of the input message
* @param first_block Is this the first block in a message or a continuation?
*/
void sha_hal_hash_block(esp_sha_type sha_type, const void *data_block, size_t block_word_len, bool first_block);
/**
* @brief Polls and waits until the SHA engine is idle
*
*/
void sha_hal_wait_idle(void);
/**
* @brief Reads the current message digest from the SHA engine
*
* @param sha_type SHA algorithm used
* @param digest_state Output buffer to which to read message digest to
*/
void sha_hal_read_digest(esp_sha_type sha_type, void *digest_state);
#if SOC_SHA_SUPPORT_RESUME
/**
* @brief Writes the message digest to the SHA engine
*
* @param sha_type The SHA algorithm type
* @param digest_state Message digest to be written to SHA engine
*/
void sha_hal_write_digest(esp_sha_type sha_type, void *digest_state);
#endif
#if SOC_SHA_SUPPORT_DMA
/**
* @brief Hashes a number of message blocks using DMA
*
* @param sha_type SHA algorithm to hash with
* @param num_blocks Number of blocks to hash
* @param first_block Is this the first block in a message or a continuation?
*/
void sha_hal_hash_dma(esp_sha_type sha_type, size_t num_blocks, bool first_block);
#endif
#if SOC_SHA_SUPPORT_SHA512_T
/**
* @brief Calculates and sets the initial digiest for SHA512_t
*
* @param t_string
* @param t_len
*/
void sha_hal_sha512_init_hash(uint32_t t_string, uint8_t t_len);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,41 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "sdkconfig.h"
/* Use enum from rom for backwards compatibility */
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/sha.h"
typedef enum SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/sha.h"
typedef SHA_TYPE esp_sha_type;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,71 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SIGMADELTA.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#include "soc/sigmadelta_periph.h"
#include "hal/sigmadelta_types.h"
#include "hal/sigmadelta_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
gpio_sd_dev_t *dev;
} sigmadelta_hal_context_t;
/**
* @brief Set Sigma-delta channel duty.
*
* @param hal Context of the HAL layer
* @param channel Sigma-delta channel number
* @param duty Sigma-delta duty of one channel, the value ranges from -128 to 127, recommended range is -90 ~ 90.
* The waveform is more like a random one in this range.
*/
#define sigmadelta_hal_set_duty(hal, channel, duty) sigmadelta_ll_set_duty((hal)->dev, channel, duty)
/**
* @brief Set Sigma-delta channel's clock pre-scale value.
*
* @param hal Context of the HAL layer
* @param channel Sigma-delta channel number
* @param prescale The divider of source clock, ranges from 0 to 255
*/
#define sigmadelta_hal_set_prescale(hal, channel, prescale) sigmadelta_ll_set_prescale((hal)->dev, channel, prescale)
/**
* @brief Init the SIGMADELTA hal and set the SIGMADELTA to the default configuration. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param sigmadelta_num The uart port number, the max port number is (SIGMADELTA_NUM_MAX -1)
*/
void sigmadelta_hal_init(sigmadelta_hal_context_t *hal, int sigmadelta_num);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,62 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SIGMADELTA port number, the max port number is (SIGMADELTA_NUM_MAX -1).
*/
typedef enum {
SIGMADELTA_PORT_0, /*!< SIGMADELTA port 0 */
SIGMADELTA_PORT_MAX, /*!< SIGMADELTA port max */
} sigmadelta_port_t;
_Static_assert(SIGMADELTA_PORT_MAX == SOC_SIGMADELTA_NUM, "Sigma-delta port num incorrect.");
/**
* @brief Sigma-delta channel list
*/
typedef enum {
SIGMADELTA_CHANNEL_0, /*!< Sigma-delta channel 0 */
SIGMADELTA_CHANNEL_1, /*!< Sigma-delta channel 1 */
SIGMADELTA_CHANNEL_2, /*!< Sigma-delta channel 2 */
SIGMADELTA_CHANNEL_3, /*!< Sigma-delta channel 3 */
#if SOC_SIGMADELTA_CHANNEL_NUM > 4
SIGMADELTA_CHANNEL_4, /*!< Sigma-delta channel 4 */
SIGMADELTA_CHANNEL_5, /*!< Sigma-delta channel 5 */
SIGMADELTA_CHANNEL_6, /*!< Sigma-delta channel 6 */
SIGMADELTA_CHANNEL_7, /*!< Sigma-delta channel 7 */
#endif
SIGMADELTA_CHANNEL_MAX, /*!< Sigma-delta channel max */
} sigmadelta_channel_t;
/**
* @brief Sigma-delta configure struct
*/
typedef struct {
sigmadelta_channel_t channel; /*!< Sigma-delta channel number */
int8_t sigmadelta_duty; /*!< Sigma-delta duty, duty ranges from -128 to 127. */
uint8_t sigmadelta_prescale; /*!< Sigma-delta prescale, prescale ranges from 0 to 255. */
uint8_t sigmadelta_gpio; /*!< Sigma-delta output io number, refer to gpio.h for more details. */
} sigmadelta_config_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,75 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/cpu_hal.h"
#include "hal/soc_ll.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_CPU_CORES_NUM > 1
// Utility functions for multicore targets
#define __SOC_HAL_PERFORM_ON_OTHER_CORES(action) { \
for (uint32_t i = 0, cur = cpu_hal_get_core_id(); i < SOC_CPU_CORES_NUM; i++) { \
if (i != cur) { \
action(i); \
} \
} \
}
#define SOC_HAL_STALL_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_stall_core);
#define SOC_HAL_UNSTALL_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_unstall_core);
#define SOC_HAL_RESET_OTHER_CORES() __SOC_HAL_PERFORM_ON_OTHER_CORES(soc_hal_reset_core);
/**
* Stall the specified CPU core.
*
* @note Has no effect if the core is already stalled - does not return an
* ESP_ERR_INVALID_STATE.
*
* @param core core to stall [0..SOC_CPU_CORES_NUM - 1]
*/
void soc_hal_stall_core(int core);
/**
* Unstall the specified CPU core.
*
* @note Has no effect if the core is already unstalled - does not return an
* ESP_ERR_INVALID_STATE.
*
* @param core core to unstall [0..SOC_CPU_CORES_NUM - 1]
*/
void soc_hal_unstall_core(int core);
#endif // SOC_CPU_CORES_NUM > 1
/**
* Reset the specified core.
*
* @param core core to reset [0..SOC_CPU_CORES_NUM - 1]
*/
#define soc_hal_reset_core(core) soc_ll_reset_core((core))
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -0,0 +1,215 @@
// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <esp_types.h>
#include <esp_bit_defs.h>
#include "esp_flash_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Definition of a common transaction. Also holds the return value. */
typedef struct {
uint8_t reserved; ///< Reserved, must be 0.
uint8_t mosi_len; ///< Output data length, in bytes
uint8_t miso_len; ///< Input data length, in bytes
uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address
uint32_t address; ///< Address to perform operation on
const uint8_t *mosi_data; ///< Output data to salve
uint8_t *miso_data; ///< [out] Input data from slave, little endian
uint32_t flags; ///< Flags for this transaction. Set to 0 for now.
#define SPI_FLASH_TRANS_FLAG_CMD16 BIT(0) ///< Send command of 16 bits
#define SPI_FLASH_TRANS_FLAG_IGNORE_BASEIO BIT(1) ///< Not applying the basic io mode configuration for this transaction
#define SPI_FLASH_TRANS_FLAG_BYTE_SWAP BIT(2) ///< Used for DTR mode, to swap the bytes of a pair of rising/falling edge
uint16_t command; ///< Command to send
uint8_t dummy_bitlen; ///< Basic dummy bits to use
} spi_flash_trans_t;
/**
* @brief SPI flash clock speed values, always refer to them by the enum rather
* than the actual value (more speed may be appended into the list).
*
* A strategy to select the maximum allowed speed is to enumerate from the
* ``ESP_FLSH_SPEED_MAX-1`` or highest frequency supported by your flash, and
* decrease the speed until the probing success.
*/
typedef enum {
ESP_FLASH_5MHZ = 0, ///< The flash runs under 5MHz
ESP_FLASH_10MHZ, ///< The flash runs under 10MHz
ESP_FLASH_20MHZ, ///< The flash runs under 20MHz
ESP_FLASH_26MHZ, ///< The flash runs under 26MHz
ESP_FLASH_40MHZ, ///< The flash runs under 40MHz
ESP_FLASH_80MHZ, ///< The flash runs under 80MHz
ESP_FLASH_SPEED_MAX, ///< The maximum frequency supported by the host is ``ESP_FLASH_SPEED_MAX-1``.
} esp_flash_speed_t;
///Lowest speed supported by the driver, currently 5 MHz
#define ESP_FLASH_SPEED_MIN ESP_FLASH_5MHZ
// These bits are not quite like "IO mode", but are able to be appended into the io mode and used by the HAL.
#define SPI_FLASH_CONFIG_CONF_BITS BIT(31) ///< OR the io_mode with this mask, to enable the dummy output feature or replace the first several dummy bits into address to meet the requirements of conf bits. (Used in DIO/QIO/OIO mode)
/** @brief Mode used for reading from SPI flash */
typedef enum {
SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed
SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed
SPI_FLASH_DOUT, ///< Data read using dual I/O
SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O
SPI_FLASH_QOUT, ///< Data read using quad I/O
SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_io_mode_t;
/// Configuration structure for the flash chip suspend feature.
typedef struct {
uint32_t sus_mask; ///< SUS/SUS1/SUS2 bit in flash register.
struct {
uint32_t cmd_rdsr :8; ///< Read flash status register(2) command.
uint32_t sus_cmd :8; ///< Flash suspend command.
uint32_t res_cmd :8; ///< Flash resume command.
uint32_t reserved :8; ///< Reserved, set to 0.
};
} spi_flash_sus_cmd_conf;
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
struct spi_flash_host_driver_s;
typedef struct spi_flash_host_driver_s spi_flash_host_driver_t;
/** SPI Flash Host driver instance */
typedef struct {
const struct spi_flash_host_driver_s* driver; ///< Pointer to the implementation function table
// Implementations can wrap this structure into their own ones, and append other data here
} spi_flash_host_inst_t ;
/** Host driver configuration and context structure. */
struct spi_flash_host_driver_s {
/**
* Configure the device-related register before transactions. This saves
* some time to re-configure those registers when we send continuously
*/
esp_err_t (*dev_config)(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
*/
esp_err_t (*common_command)(spi_flash_host_inst_t *host, spi_flash_trans_t *t);
/**
* Read flash ID.
*/
esp_err_t (*read_id)(spi_flash_host_inst_t *host, uint32_t *id);
/**
* Erase whole flash chip.
*/
void (*erase_chip)(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address.
*/
void (*erase_sector)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific block by its start address.
*/
void (*erase_block)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Read the status of the flash chip.
*/
esp_err_t (*read_status)(spi_flash_host_inst_t *host, uint8_t *out_sr);
/**
* Disable write protection.
*/
esp_err_t (*set_write_protect)(spi_flash_host_inst_t *host, bool wp);
/**
* Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length.
*/
void (*program_page)(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/** Check whether given buffer can be directly used to write */
bool (*supports_direct_write)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for write data. The `program_page` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to write
* @param len Length request to write
* @param align_addr Output of the aligned address to write to
* @param page_size Physical page size of the flash chip
* @return Length that can be actually written in one `program_page` call
*/
int (*write_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr,
uint32_t page_size);
/**
* Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length.
*/
esp_err_t (*read)(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for read data. The `read` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to read
* @param len Length request to read
* @param align_addr Output of the aligned address to read
* @param page_size Physical page size of the flash chip
* @return Length that can be actually read in one `read` call
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check the host status, 0:busy, 1:idle, 2:suspended.
*/
uint32_t (*host_status)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
esp_err_t (*configure_host_io_mode)(spi_flash_host_inst_t *host, uint32_t command,
uint32_t addr_bitlen, int dummy_bitlen_base,
esp_flash_io_mode_t io_mode);
/**
* Internal use, poll the HW until the last operation is done.
*/
void (*poll_cmd_done)(spi_flash_host_inst_t *host);
/**
* For some host (SPI1), they are shared with a cache. When the data is
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
/**
* Suspend check erase/program operation, reserved for ESP32-C3 and ESP32-S3 spi flash ROM IMPL.
*/
void (*check_suspend)(spi_flash_host_inst_t *host);
/**
* Resume flash from suspend manually
*/
void (*resume)(spi_flash_host_inst_t *host);
/**
* Set flash in suspend status manually
*/
void (*suspend)(spi_flash_host_inst_t *host);
/**
* Suspend feature setup for setting cmd and status register mask.
*/
esp_err_t (*sus_setup)(spi_flash_host_inst_t *host, const spi_flash_sus_cmd_conf *sus_conf);
};
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -0,0 +1,163 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for SPI slave (common part)
// SPI slave HAL usages:
// 1. initialize the bus
// 2. initialize the DMA descriptors if DMA used
// 3. call setup_device to update parameters for the device
// 4. prepare data to send, and prepare the receiving buffer
// 5. trigger user defined SPI transaction to start
// 6. wait until the user transaction is done
// 7. store the received data and get the length
// 8. check and reset the DMA (if needed) before the next transaction
#pragma once
#include <esp_types.h>
#include "soc/lldesc.h"
#include "soc/spi_struct.h"
#include "soc/soc_caps.h"
#include "hal/spi_ll.h"
/**
* Context that should be maintained by both the driver and the HAL.
*/
typedef struct {
/* configured by driver at initialization, don't touch */
spi_dev_t *hw; ///< Beginning address of the peripheral registers.
spi_dma_dev_t *dma_in; ///< Address of the DMA peripheral registers which stores the data received from a peripheral into RAM.
spi_dma_dev_t *dma_out; ///< Address of the DMA peripheral registers which transmits the data from RAM to a peripheral.
/* should be configured by driver at initialization */
lldesc_t *dmadesc_rx; /**< Array of DMA descriptor used by the TX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
lldesc_t *dmadesc_tx; /**< Array of DMA descriptor used by the RX DMA.
* The amount should be larger than dmadesc_n. The driver should ensure that
* the data to be sent is shorter than the descriptors can hold.
*/
int dmadesc_n; ///< The amount of descriptors of both ``dmadesc_tx`` and ``dmadesc_rx`` that the HAL can use.
uint32_t tx_dma_chan; ///< TX DMA channel
uint32_t rx_dma_chan; ///< RX DMA channel
/*
* configurations to be filled after ``spi_slave_hal_init``. Updated to
* peripheral registers when ``spi_slave_hal_setup_device`` is called.
*/
struct {
uint32_t rx_lsbfirst : 1;
uint32_t tx_lsbfirst : 1;
uint32_t use_dma : 1;
};
int mode;
/*
* Transaction specific (data), all these parameters will be updated to the
* peripheral every transaction.
*/
uint32_t bitlen; ///< Expected maximum length of the transaction, in bits.
const void *tx_buffer; ///< Data to be sent
void *rx_buffer; ///< Buffer to hold the received data.
/* Other transaction result after one transaction */
uint32_t rcv_bitlen; ///< Length of the last transaction, in bits.
} spi_slave_hal_context_t;
typedef struct {
uint32_t host_id; ///< SPI controller ID
spi_dma_dev_t *dma_in; ///< Input DMA(DMA -> RAM) peripheral register address
spi_dma_dev_t *dma_out; ///< Output DMA(RAM -> DMA) peripheral register address
} spi_slave_hal_config_t;
/**
* Init the peripheral and the context.
*
* @param hal Context of the HAL layer.
* @param host_id Index of the SPI peripheral. 0 for SPI1, 1 for HSPI (SPI2) and 2 for VSPI (SPI3).
*/
void spi_slave_hal_init(spi_slave_hal_context_t *hal, const spi_slave_hal_config_t *hal_config);
/**
* Deinit the peripheral (and the context if needed).
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_deinit(spi_slave_hal_context_t *hal);
/**
* Setup device-related configurations according to the settings in the context.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_setup_device(const spi_slave_hal_context_t *hal);
/**
* Prepare the data for the current transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal);
/**
* Trigger start a user-defined transaction.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal);
/**
* Check whether the transaction is done (trans_done is set).
*
* @param hal Context of the HAL layer.
*/
bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal);
/**
* Post transaction operations, fetch data from the buffer and recored the length.
*
* @param hal Context of the HAL layer.
*/
void spi_slave_hal_store_result(spi_slave_hal_context_t *hal);
/**
* Get the length of last transaction, in bits. Should be called after ``spi_slave_hal_store_result``.
*
* Note that if last transaction is longer than configured before, the return
* value will be truncated to the configured length.
*
* @param hal Context of the HAL layer.
*
* @return Length of the last transaction, in bits.
*/
uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal);
/**
* Check whether we need to reset the DMA according to the status of last transactions.
*
* In ESP32, sometimes we may need to reset the DMA for the slave before the
* next transaction. Call this to check it.
*
* @param hal Context of the HAL layer.
*
* @return true if reset is needed, else false.
*/
bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal);

View File

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

View File

@@ -0,0 +1,64 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "esp_attr.h"
#include <esp_bit_defs.h>
#include "soc/soc_caps.h"
#include "sdkconfig.h"
/**
* @brief Enum with the three SPI peripherals that are software-accessible in it
*/
typedef enum {
//SPI1 can be used as GPSPI only on ESP32
SPI1_HOST=0, ///< SPI1
SPI2_HOST=1, ///< SPI2
SPI3_HOST=2, ///< SPI3
} spi_host_device_t;
/// SPI Events
typedef enum {
SPI_EV_BUF_TX = BIT(0), ///< The buffer has sent data to master, Slave HD only
SPI_EV_BUF_RX = BIT(1), ///< The buffer has received data from master, Slave HD only
SPI_EV_SEND = BIT(2), ///< Slave has loaded some data to DMA, and master has received certain number of the data, the number is determined by master. Slave HD only
SPI_EV_RECV = BIT(3), ///< Slave has received certain number of data from master, the number is determined by master. Slave HD only.
SPI_EV_CMD9 = BIT(4), ///< Received CMD9 from master, Slave HD only
SPI_EV_CMDA = BIT(5), ///< Received CMDA from master, Slave HD only
SPI_EV_TRANS = BIT(6), ///< A transaction has done
} spi_event_t;
FLAG_ATTR(spi_event_t)
/** @cond */ //Doxy command to hide preprocessor definitions from docs */
//alias for different chips
#ifdef CONFIG_IDF_TARGET_ESP32
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI2_HOST
#define VSPI_HOST SPI3_HOST
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
// SPI_HOST (SPI1_HOST) is not supported by the SPI Master and SPI Slave driver on ESP32-S2 and later
#define SPI_HOST SPI1_HOST
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI3_HOST
#elif CONFIG_IDF_TARGET_ESP32C3
/* No SPI3_host on C3 */
#define SPI_HOST SPI1_HOST
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI2_HOST
#endif
/** @endcond */

View File

@@ -0,0 +1,92 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "hal/systimer_types.h"
/**
* @brief enable systimer counter
*/
void systimer_hal_enable_counter(systimer_counter_id_t counter_id);
/**
* @brief get current counter value
*/
uint64_t systimer_hal_get_counter_value(systimer_counter_id_t counter_id);
/**
* @brief get current time (in microseconds)
*/
uint64_t systimer_hal_get_time(systimer_counter_id_t counter_id);
/*
* @brief set alarm target value (used in one-shot mode)
*/
void systimer_hal_set_alarm_target(systimer_alarm_id_t alarm_id, uint64_t target);
/**
* @brief set alarm period value (used in period mode)
*/
void systimer_hal_set_alarm_period(systimer_alarm_id_t alarm_id, uint32_t period);
/**
* @brief get alarm time
*/
uint64_t systimer_hal_get_alarm_value(systimer_alarm_id_t alarm_id);
/**
* @brief enable alarm interrupt
*/
void systimer_hal_enable_alarm_int(systimer_alarm_id_t alarm_id);
/**
* @brief select alarm mode
*/
void systimer_hal_select_alarm_mode(systimer_alarm_id_t alarm_id, systimer_alarm_mode_t mode);
/**
* @brief update systimer step when apb clock gets changed
*/
void systimer_hal_on_apb_freq_update(uint32_t apb_ticks_per_us);
/**
* @brief move systimer counter value forward or backward
*/
void systimer_hal_counter_value_advance(systimer_counter_id_t counter_id, int64_t time_us);
/**
* @brief initialize systimer in HAL layer
*/
void systimer_hal_init(void);
/**
* @brief connect alarm unit to selected counter
*/
void systimer_hal_connect_alarm_counter(systimer_alarm_id_t alarm_id, systimer_counter_id_t counter_id);
/**
* @brief set if a counter should be stalled when CPU is halted by the debugger
*/
void systimer_hal_counter_can_stall_by_cpu(uint32_t counter_id, uint32_t cpu_id, bool can);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,74 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "soc/soc_caps.h"
/*
* @brief The structure of the counter value in systimer
*
*/
typedef struct {
union {
struct {
uint64_t lo : SOC_SYSTIMER_BIT_WIDTH_LO; /*!< Low part of counter value */
uint64_t hi : SOC_SYSTIMER_BIT_WIDTH_HI; /*!< High part of counter value */
};
uint64_t val; /*!< counter value */
};
} systimer_counter_value_t;
/** @cond */
_Static_assert(sizeof(systimer_counter_value_t) == 8, "systimer_counter_value_t should occupy 8 bytes in memory");
/** @endcond */
/**
* @brief systimer counter ID
*
*/
typedef enum {
SYSTIMER_COUNTER_0, /*!< systimer counter 0 */
#if SOC_SYSTIMER_COUNTER_NUM > 1
SYSTIMER_COUNTER_1, /*!< systimer counter 1 */
#endif
} systimer_counter_id_t;
/**
* @brief systimer alarm ID
*
*/
typedef enum {
SYSTIMER_ALARM_0, /*!< systimer alarm 0 */
SYSTIMER_ALARM_1, /*!< systimer alarm 1 */
SYSTIMER_ALARM_2, /*!< systimer alarm 2 */
} systimer_alarm_id_t;
/**
* @brief systimer alarm mode
*
*/
typedef enum {
SYSTIMER_ALARM_MODE_ONESHOT, /*!< systimer alarm oneshot mode */
SYSTIMER_ALARM_MODE_PERIOD, /*!< systimer alarm period mode */
} systimer_alarm_mode_t;
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,330 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use in application code.
* See readme.md in hal/include/hal/readme.md
******************************************************************************/
// The HAL layer for Timer Group.
// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#include "hal/timer_ll.h"
#include "hal/timer_types.h"
/**
* Context that should be maintained by both the driver and the HAL
*/
typedef struct {
timg_dev_t *dev;
timer_idx_t idx;
} timer_hal_context_t;
/**
* @brief Init the timer hal. This function should be called first before other hal layer function is called
*
* @param hal Context of the HAL layer
* @param group_num The timer group number
* @param timer_num The timer number
*
* @return None
*/
void timer_hal_init(timer_hal_context_t *hal, timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Get interrupt status register address and corresponding control bits mask
*
* @param hal Context of the HAL layer
* @param status_reg[out] interrupt status register address
* @param mask_bit[out] control bits mask
*/
void timer_hal_get_status_reg_mask_bit(timer_hal_context_t *hal, uint32_t *status_reg, uint32_t *mask_bit);
/**
* @brief Set timer clock prescale value
*
* @param hal Context of the HAL layer
* @param divider Prescale value
*
* @return None
*/
#define timer_hal_set_divider(hal, divider) timer_ll_set_divider((hal)->dev, (hal)->idx, divider)
/**
* @brief Get timer clock prescale value
*
* @param hal Context of the HAL layer
* @param divider Pointer to accept the prescale value
*
* @return None
*/
#define timer_hal_get_divider(hal, divider) timer_ll_get_divider((hal)->dev, (hal)->idx, divider)
/**
* @brief Load counter value into time-base counter
*
* @param hal Context of the HAL layer
* @param load_val Counter value
*
* @return None
*/
#define timer_hal_set_counter_value(hal, load_val) timer_ll_set_counter_value((hal)->dev, (hal)->idx, load_val)
/**
* @brief Get counter value from time-base counter
*
* @param hal Context of the HAL layer
* @param timer_val Pointer to accept the counter value
*
* @return None
*/
#define timer_hal_get_counter_value(hal, timer_val) timer_ll_get_counter_value((hal)->dev, (hal)->idx, timer_val)
/**
* @brief Set counter mode, include increment mode and decrement mode.
*
* @param hal Context of the HAL layer
* @param increase_en True to increment mode, fasle to decrement mode
*
* @return None
*/
#define timer_hal_set_counter_increase(hal, increase_en) timer_ll_set_counter_increase((hal)->dev, (hal)->idx, increase_en)
/**
* @brief Get counter mode, include increment mode and decrement mode.
*
* @param hal Context of the HAL layer
* @param counter_dir Pointer to accept the counter mode
*
* @return
* - true Increment mode
* - false Decrement mode
*/
#define timer_hal_get_counter_increase(hal) timer_ll_get_counter_increase((hal)->dev, (hal)->idx)
/**
* @brief Set counter status, enable or disable counter.
*
* @param hal Context of the HAL layer
* @param counter_en True to enable counter, false to disable counter
*
* @return None
*/
#define timer_hal_set_counter_enable(hal, counter_en) timer_ll_set_counter_enable((hal)->dev, (hal)->idx, counter_en)
/**
* @brief Get counter status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable counter
* - false Disable conuter
*/
#define timer_hal_get_counter_enable(hal) timer_ll_get_counter_enable((hal)->dev, (hal)->idx)
/**
* @brief Set auto reload mode.
*
* @param hal Context of the HAL layer
* @param auto_reload_en True to enable auto reload mode, flase to disable auto reload mode
*
* @return None
*/
#define timer_hal_set_auto_reload(hal, auto_reload_en) timer_ll_set_auto_reload((hal)->dev, (hal)->idx, auto_reload_en)
/**
* @brief Get auto reload mode.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable auto reload mode
* - false Disable auto reload mode
*/
#define timer_hal_get_auto_reload(hal) timer_ll_get_auto_reload((hal)->dev, (hal)->idx)
/**
* @brief Set the counter value to trigger the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_value Counter value to trigger the alarm
*
* @return None
*/
#define timer_hal_set_alarm_value(hal, alarm_value) timer_ll_set_alarm_value((hal)->dev, (hal)->idx, alarm_value)
/**
* @brief Get the counter value to trigger the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_value Pointer to accept the counter value to trigger the alarm
*
* @return None
*/
#define timer_hal_get_alarm_value(hal, alarm_value) timer_ll_get_alarm_value((hal)->dev, (hal)->idx, alarm_value)
/**
* @brief Set the alarm status, enable or disable the alarm.
*
* @param hal Context of the HAL layer
* @param alarm_en True to enable alarm, false to disable alarm
*
* @return None
*/
#define timer_hal_set_alarm_enable(hal, alarm_en) timer_ll_set_alarm_enable((hal)->dev, (hal)->idx, alarm_en)
/**
* @brief Get the alarm status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable alarm
* - false Disable alarm
*/
#define timer_hal_get_alarm_enable(hal) timer_ll_get_alarm_enable((hal)->dev, (hal)->idx)
/**
* @brief Set the level interrupt status, enable or disable the level interrupt.
*
* @param hal Context of the HAL layer
* @param level_int_en True to enable level interrupt, false to disable level interrupt
*
* @return None
*/
#define timer_hal_set_level_int_enable(hal, level_int_en) timer_ll_set_level_int_enable((hal)->dev, (hal)->idx, level_int_en)
/**
* @brief Get the level interrupt status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable level interrupt
* - false Disable level interrupt
*/
#define timer_hal_get_level_int_enable(hal) timer_ll_get_level_int_enable((hal)->dev, (hal)->idx)
/**
* @brief Set the edge interrupt status, enable or disable the edge interrupt.
*
* @param hal Context of the HAL layer
* @param edge_int_en True to enable edge interrupt, false to disable edge interrupt
*
* @return None
*/
#define timer_hal_set_edge_int_enable(hal, edge_int_en) timer_ll_set_edge_int_enable((hal)->dev, (hal)->idx, edge_int_en)
/**
* @brief Get the edge interrupt status.
*
* @param hal Context of the HAL layer
*
* @return
* - true Enable edge interrupt
* - false Disable edge interrupt
*/
#define timer_hal_get_edge_int_enable(hal) timer_ll_get_edge_int_enable((hal)->dev, (hal)->idx)
/**
* @brief Enable timer interrupt.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_intr_enable(hal) timer_ll_intr_enable((hal)->dev, (hal)->idx)
/**
* @brief Disable timer interrupt.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_intr_disable(hal) timer_ll_intr_disable((hal)->dev, (hal)->idx)
/**
* @brief Clear interrupt status.
*
* @param hal Context of the HAL layer
*
* @return None
*/
#define timer_hal_clear_intr_status(hal) timer_ll_clear_intr_status((hal)->dev, (hal)->idx)
/**
* @brief Get interrupt status.
*
* @param hal Context of the HAL layer
* @param intr_status Interrupt status
*
* @return None
*/
#define timer_hal_get_intr_status(hal, intr_status) timer_ll_get_intr_status((hal)->dev, intr_status)
/**
* @brief Get interrupt raw status.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_raw_status Interrupt raw status
*
* @return None
*/
#define timer_hal_get_intr_raw_status(group_num, intr_raw_status) timer_ll_get_intr_raw_status(group_num, intr_raw_status)
/**
* @brief Get interrupt status register address.
*
* @param hal Context of the HAL layer
*
* @return Interrupt status register address
*/
#define timer_hal_get_intr_status_reg(hal) timer_ll_get_intr_status_reg((hal)->dev)
#if SOC_TIMER_GROUP_SUPPORT_XTAL
/**
* @brief Set clock source.
*
* @param hal Context of the HAL layer
* @param use_xtal_en True to use XTAL clock, flase to use APB clock
*
* @return None
*/
#define timer_hal_set_use_xtal(hal, use_xtal_en) timer_ll_set_use_xtal((hal)->dev, (hal)->idx, use_xtal_en)
/**
* @brief Get clock source.
*
* @param hal Context of the HAL layer
*
* @return
* - true Use XTAL clock
* - false Use APB clock
*/
#define timer_hal_get_use_xtal(hal) timer_ll_get_use_xtal((hal)->dev, (hal)->idx)
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,135 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <esp_bit_defs.h>
#include "esp_attr.h"
#include "soc/soc_caps.h"
/**
* @brief Selects a Timer-Group out of 2 available groups
*/
typedef enum {
TIMER_GROUP_0 = 0, /*!<Hw timer group 0*/
#if SOC_TIMER_GROUPS > 1
TIMER_GROUP_1 = 1, /*!<Hw timer group 1*/
#endif
TIMER_GROUP_MAX,
} timer_group_t;
/**
* @brief Select a hardware timer from timer groups
*/
typedef enum {
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
#endif
TIMER_MAX,
} timer_idx_t;
/**
* @brief Decides the direction of counter
*/
typedef enum {
TIMER_COUNT_DOWN = 0, /*!< Descending Count from cnt.high|cnt.low*/
TIMER_COUNT_UP = 1, /*!< Ascending Count from Zero*/
TIMER_COUNT_MAX
} timer_count_dir_t;
/**
* @brief Decides whether timer is on or paused
*/
typedef enum {
TIMER_PAUSE = 0, /*!<Pause timer counter*/
TIMER_START = 1, /*!<Start timer counter*/
} timer_start_t;
/**
* @brief Interrupt types of the timer.
*/
//this is compatible with the value of esp32.
typedef enum {
TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1
TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */
TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */
#else
TIMER_INTR_WDT = BIT(1), /*!< interrupt of watchdog */
#endif
TIMER_INTR_NONE = 0
} timer_intr_t;
FLAG_ATTR(timer_intr_t)
/**
* @brief Decides whether to enable alarm mode
*/
typedef enum {
TIMER_ALARM_DIS = 0, /*!< Disable timer alarm*/
TIMER_ALARM_EN = 1, /*!< Enable timer alarm*/
TIMER_ALARM_MAX
} timer_alarm_t;
/**
* @brief Select interrupt type if running in alarm mode.
*/
typedef enum {
TIMER_INTR_LEVEL = 0, /*!< Interrupt mode: level mode*/
TIMER_INTR_MAX
} timer_intr_mode_t;
/**
* @brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
*/
typedef enum {
TIMER_AUTORELOAD_DIS = 0, /*!< Disable auto-reload: hardware will not load counter value after an alarm event*/
TIMER_AUTORELOAD_EN = 1, /*!< Enable auto-reload: hardware will load counter value after an alarm event*/
TIMER_AUTORELOAD_MAX,
} timer_autoreload_t;
#if SOC_TIMER_GROUP_SUPPORT_XTAL
/**
* @brief Select timer source clock.
*/
typedef enum {
TIMER_SRC_CLK_APB = 0, /*!< Select APB as the source clock*/
TIMER_SRC_CLK_XTAL = 1, /*!< Select XTAL as the source clock*/
} timer_src_clk_t;
#endif
/**
* @brief Data structure with timer's configuration settings
*/
typedef struct {
timer_alarm_t alarm_en; /*!< Timer alarm enable */
timer_start_t counter_en; /*!< Counter enable */
timer_intr_mode_t intr_type; /*!< Interrupt mode */
timer_count_dir_t counter_dir; /*!< Counter direction */
timer_autoreload_t auto_reload; /*!< Timer auto-reload */
uint32_t divider; /*!< Counter clock divider. The divider's range is from from 2 to 65536. */
#if SOC_TIMER_GROUP_SUPPORT_XTAL
timer_src_clk_t clk_src; /*!< Use XTAL as source clock. */
#endif
} timer_config_t;
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

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

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