Initial Esp32c3 Support (#5060)

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

View File

@ -0,0 +1,100 @@
// Copyright 2019-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 "driver/adc_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/*************************************/
/* Digital controller filter setting */
/*************************************/
/**
* @brief Reset adc digital controller filter.
*
* @param idx Filter index.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_reset(adc_digi_filter_idx_t idx);
/**
* @brief Set adc digital controller filter configuration.
*
* @param idx Filter index.
* @param config See ``adc_digi_filter_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_set_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
/**
* @brief Get adc digital controller filter configuration.
*
* @param idx Filter index.
* @param config See ``adc_digi_filter_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_get_config(adc_digi_filter_idx_t idx, adc_digi_filter_t *config);
/**
* @brief Enable/disable adc digital controller filter.
* Filtering the ADC data to obtain smooth data at higher sampling rates.
*
* @param idx Filter index.
* @param enable Enable/Disable filter.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_filter_enable(adc_digi_filter_idx_t idx, bool enable);
/**************************************/
/* Digital controller monitor setting */
/**************************************/
/**
* @brief Config monitor of adc digital controller.
*
* @param idx Monitor index.
* @param config See ``adc_digi_monitor_t``.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_monitor_set_config(adc_digi_monitor_idx_t idx, adc_digi_monitor_t *config);
/**
* @brief Enable/disable monitor of adc digital controller.
*
* @param idx Monitor index.
* @param enable True or false enable monitor.
*
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_monitor_enable(adc_digi_monitor_idx_t idx, bool enable);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,99 @@
// 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 <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TSENS_DAC_L0 = 0, /*!< offset = -2, measure range: 50℃ ~ 125℃, error < 3℃. */
TSENS_DAC_L1, /*!< offset = -1, measure range: 20℃ ~ 100℃, error < 2℃. */
TSENS_DAC_L2, /*!< offset = 0, measure range:-10℃ ~ 80℃, error < 1℃. */
TSENS_DAC_L3, /*!< offset = 1, measure range:-30℃ ~ 50℃, error < 2℃. */
TSENS_DAC_L4, /*!< offset = 2, measure range:-40℃ ~ 20℃, error < 3℃. */
TSENS_DAC_MAX,
TSENS_DAC_DEFAULT = TSENS_DAC_L2,
} temp_sensor_dac_offset_t;
/**
* @brief Configuration for temperature sensor reading
*/
typedef struct {
temp_sensor_dac_offset_t dac_offset; /*!< The temperature measurement range is configured with a built-in temperature offset DAC. */
uint8_t clk_div; /*!< Default: 6 */
} temp_sensor_config_t;
#define TSENS_CONFIG_DEFAULT() {.dac_offset = TSENS_DAC_L2, \
.clk_div = 6}
/**
* @brief Set parameter of temperature sensor.
* @param tsens
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens);
/**
* @brief Get parameter of temperature sensor.
* @param tsens
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_get_config(temp_sensor_config_t *tsens);
/**
* @brief Start temperature sensor measure.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG
*/
esp_err_t temp_sensor_start(void);
/**
* @brief Stop temperature sensor measure.
* @return
* - ESP_OK Success
*/
esp_err_t temp_sensor_stop(void);
/**
* @brief Read temperature sensor raw data.
* @param tsens_out Pointer to raw data, Range: 0 ~ 255
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG `tsens_out` is NULL
* - ESP_ERR_INVALID_STATE temperature sensor dont start
*/
esp_err_t temp_sensor_read_raw(uint32_t *tsens_out);
/**
* @brief Read temperature sensor data that is converted to degrees Celsius.
* @note Should not be called from interrupt.
* @param celsius The measure output value.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG ARG is NULL.
* - ESP_ERR_INVALID_STATE The ambient temperature is out of range.
*/
esp_err_t temp_sensor_read_celsius(float *celsius);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,64 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 "esp_err.h"
/**
* @brief For WIFI module to claim the usage of ADC2.
*
* Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``.
* The WIFI module may have to wait for a short time for the current conversion (if exist) to finish.
*
* @return
* - ESP_OK success
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
*/
esp_err_t adc2_wifi_acquire(void);
/**
* @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work.
*
* Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``.
* Call this function to release the occupation of ADC2 by WIFI.
*
* @return always return ESP_OK.
*/
esp_err_t adc2_wifi_release(void);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3
/**
* @brief This API help ADC2 calibration constructor be linked.
*
* @note This is a private function, Don't call `adc2_cal_include` in user code.
*/
void adc2_cal_include(void);
#else
/**
* @brief There's no calibration involved on this chip.
*
* @note This is a private function, Don't call `adc2_cal_include` in user code.
*/
#define adc2_cal_include()
#endif //CONFIG_IDF_TARGET_*
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,552 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 "sdkconfig.h"
#include "driver/gpio.h"
#include "hal/adc_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */
ADC1_CHANNEL_MAX,
} adc1_channel_t;
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO1 */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO2 */
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO3 */
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO4 */
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO5 */
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO6 */
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO7 */
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO8 */
ADC1_CHANNEL_8, /*!< ADC1 channel 6 is GPIO9 */
ADC1_CHANNEL_9, /*!< ADC1 channel 7 is GPIO10 */
ADC1_CHANNEL_MAX,
} adc1_channel_t;
#elif CONFIG_IDF_TARGET_ESP32C3
/**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO0 */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO1 */
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO2 */
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO3 */
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO4 */
ADC1_CHANNEL_MAX,
} adc1_channel_t;
#endif // CONFIG_IDF_TARGET_*
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // TODO ESP32-S3 channels are wrong IDF-1776
/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum {
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */
ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */
ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */
ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */
ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */
ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */
ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */
ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */
ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
ADC2_CHANNEL_MAX,
} adc2_channel_t;
#elif CONFIG_IDF_TARGET_ESP32C3
/**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
typedef enum {
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */
ADC2_CHANNEL_MAX,
} adc2_channel_t;
#endif
/**
* @brief ADC rtc controller attenuation option.
*
* @note This definitions are only for being back-compatible
*/
#define ADC_ATTEN_0db ADC_ATTEN_DB_0
#define ADC_ATTEN_2_5db ADC_ATTEN_DB_2_5
#define ADC_ATTEN_6db ADC_ATTEN_DB_6
#define ADC_ATTEN_11db ADC_ATTEN_DB_11
/**
* The default (max) bit width of the ADC of current version. You can also get the maximum bitwidth
* by `SOC_ADC_MAX_BITWIDTH` defined in soc_caps.h.
*/
#define ADC_WIDTH_BIT_DEFAULT (ADC_WIDTH_MAX-1)
//this definitions are only for being back-compatible
#define ADC_WIDTH_9Bit ADC_WIDTH_BIT_9
#define ADC_WIDTH_10Bit ADC_WIDTH_BIT_10
#define ADC_WIDTH_11Bit ADC_WIDTH_BIT_11
#define ADC_WIDTH_12Bit ADC_WIDTH_BIT_12
#if CONFIG_IDF_TARGET_ESP32C3
/**
* @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports
*/
#define ADC_MAX_DELAY UINT32_MAX
#endif
/**
* @brief ADC digital controller encode option.
*
* @deprecated The ESP32-S2 doesn't use I2S DMA. Call ``adc_digi_output_format_t`` instead.
*/
typedef enum {
ADC_ENCODE_12BIT, /*!< ADC to DMA data format, , [15:12]-channel [11:0]-12 bits ADC data */
ADC_ENCODE_11BIT, /*!< ADC to DMA data format, [15]-unit, [14:11]-channel [10:0]-11 bits ADC data */
ADC_ENCODE_MAX,
} adc_i2s_encode_t;
#if CONFIG_IDF_TARGET_ESP32C3
//This feature is currently supported on ESP32C3, will be supported on other chips soon
/**
* @brief Digital ADC DMA configuration
*/
typedef struct adc_digi_init_config_s {
uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed. When this length is reached, driver will dump out all the old data and start to store them again.
uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt.
uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
} adc_digi_init_config_t;
#endif
/*---------------------------------------------------------------
Common setting
---------------------------------------------------------------*/
/**
* @brief Enable ADC power
* @deprecated Use adc_power_acquire and adc_power_release instead.
*/
void adc_power_on(void) __attribute__((deprecated));
/**
* @brief Power off SAR ADC
* @deprecated Use adc_power_acquire and adc_power_release instead.
* This function will force power down for ADC.
* This function is deprecated because forcing power ADC power off may
* disrupt operation of other components which may be using the ADC.
*/
void adc_power_off(void) __attribute__((deprecated));
/**
* @brief Increment the usage counter for ADC module.
* ADC will stay powered on while the counter is greater than 0.
* Call adc_power_release when done using the ADC.
*/
void adc_power_acquire(void);
/**
* @brief Decrement the usage counter for ADC module.
* ADC will stay powered on while the counter is greater than 0.
* Call this function when done using the ADC.
*/
void adc_power_release(void);
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* @brief Initialize ADC pad
* @param adc_unit ADC unit index
* @param channel ADC channel index
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
/*---------------------------------------------------------------
ADC Single Read Setting
---------------------------------------------------------------*/
/**
* @brief Get the GPIO number of a specific ADC1 channel.
*
* @param channel Channel to get the GPIO number
* @param gpio_num output buffer to hold the GPIO number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channel not valid
*/
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Set the attenuation of a particular channel on ADC1, and configure its associated GPIO pin mux.
*
* The default ADC voltage is for attenuation 0 dB and listed in the table below.
* By setting higher attenuation it is possible to read higher voltages.
*
* Due to ADC characteristics, most accurate results are obtained within the "suggested range"
* shown in the following table.
*
* +----------+-------------+-----------------+
* | | attenuation | suggested range |
* | SoC | (dB) | (mV) |
* +==========+=============+=================+
* | | 0 | 100 ~ 950 |
* | +-------------+-----------------+
* | | 2.5 | 100 ~ 1250 |
* | ESP32 +-------------+-----------------+
* | | 6 | 150 ~ 1750 |
* | +-------------+-----------------+
* | | 11 | 150 ~ 2450 |
* +----------+-------------+-----------------+
* | | 0 | 0 ~ 750 |
* | +-------------+-----------------+
* | | 2.5 | 0 ~ 1050 |
* | ESP32-S2 +-------------+-----------------+
* | | 6 | 0 ~ 1300 |
* | +-------------+-----------------+
* | | 11 | 0 ~ 2500 |
* +----------+-------------+-----------------+
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @note For any given channel, this function must be called before the first time ``adc1_get_raw()`` is called for that channel.
*
* @note This function can be called multiple times to configure multiple
* ADC channels simultaneously. You may call ``adc1_get_raw()`` only after configuring a channel.
*
* @param channel ADC1 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);
/**
* @brief Configure ADC1 capture width, meanwhile enable output invert for ADC1.
* The configuration is for all channels of ADC1
* @param width_bit Bit capture width for ADC1
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc1_config_width(adc_bits_width_t width_bit);
/**
* @brief Take an ADC1 reading from a single channel.
* @note ESP32:
* When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on,
* the input of GPIO36 and GPIO39 will be pulled down for about 80ns.
* When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39.
* Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue.
* As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA),
* but will remove the glitches on GPIO36 and GPIO39.
*
* @note Call ``adc1_config_width()`` before the first time this
* function is called.
*
* @note For any given channel, adc1_config_channel_atten(channel)
* must be called before the first time this function is called. Configuring
* a new channel does not prevent a previously configured channel from being read.
*
* @param channel ADC1 channel to read
*
* @return
* - -1: Parameter error
* - Other: ADC1 channel reading.
*/
int adc1_get_raw(adc1_channel_t channel);
#if !CONFIG_IDF_TARGET_ESP32C3
/**
* @brief Set ADC data invert
* @param adc_unit ADC unit index
* @param inv_en whether enable data invert
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en);
/**
* @brief Set ADC source clock
* @param clk_div ADC clock divider, ADC clock is divided from APB clock
* @return
* - ESP_OK success
*/
esp_err_t adc_set_clk_div(uint8_t clk_div);
/**
* @brief Configure ADC capture width.
*
* @param adc_unit ADC unit index
* @param width_bit Bit capture width for ADC unit.
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
/**
* @brief Configure ADC1 to be usable by the ULP
*
* This function reconfigures ADC1 to be controlled by the ULP.
* Effect of this function can be reverted using ``adc1_get_raw()`` function.
*
* Note that adc1_config_channel_atten, ``adc1_config_width()`` functions need
* to be called to configure ADC1 channels, before ADC1 is used by the ULP.
*/
void adc1_ulp_enable(void);
#endif //#if !CONFIG_IDF_TARGET_ESP32C3
/**
* @brief Get the GPIO number of a specific ADC2 channel.
*
* @param channel Channel to get the GPIO number
*
* @param gpio_num output buffer to hold the GPIO number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channel not valid
*/
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Configure the ADC2 channel, including setting attenuation.
*
* The default ADC voltage is for attenuation 0 dB and listed in the table below.
* By setting higher attenuation it is possible to read higher voltages.
*
* Due to ADC characteristics, most accurate results are obtained within the "suggested range"
* shown in the following table.
*
* +----------+-------------+-----------------+
* | | attenuation | suggested range |
* | SoC | (dB) | (mV) |
* +==========+=============+=================+
* | | 0 | 100 ~ 950 |
* | +-------------+-----------------+
* | | 2.5 | 100 ~ 1250 |
* | ESP32 +-------------+-----------------+
* | | 6 | 150 ~ 1750 |
* | +-------------+-----------------+
* | | 11 | 150 ~ 2450 |
* +----------+-------------+-----------------+
* | | 0 | 0 ~ 750 |
* | +-------------+-----------------+
* | | 2.5 | 0 ~ 1050 |
* | ESP32-S2 +-------------+-----------------+
* | | 6 | 0 ~ 1300 |
* | +-------------+-----------------+
* | | 11 | 0 ~ 2500 |
* +----------+-------------+-----------------+
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @note This function also configures the input GPIO pin mux to
* connect it to the ADC2 channel. It must be called before calling
* ``adc2_get_raw()`` for this channel.
*
* @note For any given channel, this function must be called before the first time ``adc2_get_raw()`` is called for that channel.
*
* @param channel ADC2 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten);
/**
* @brief Take an ADC2 reading on a single channel
*
* @note ESP32:
* When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on,
* the input of GPIO36 and GPIO39 will be pulled down for about 80ns.
* When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39.
* Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue.
* As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA),
* but will remove the glitches on GPIO36 and GPIO39.
*
*
* @note ESP32:
* For a given channel, ``adc2_config_channel_atten()``
* must be called before the first time this function is called. If Wi-Fi is started via ``esp_wifi_start()``, this
* function will always fail with ``ESP_ERR_TIMEOUT``.
*
* @note ESP32-S2:
* ADC2 support hardware 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. Default priority: Wi-Fi > RTC > Digital;
*
* @param channel ADC2 channel to read
* @param width_bit Bit capture width for ADC2
* @param raw_out the variable to hold the output data.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT ADC2 is being used by other controller and the request timed out.
* - ESP_ERR_INVALID_STATE The controller status is invalid. Please try again.
*/
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out);
/**
* @brief Output ADC1 or ADC2's reference voltage to ``adc2_channe_t``'s IO.
*
* 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_unit ADC unit index
* @param[in] gpio GPIO number (Only ADC2's channels IO are supported)
*
* @return
* - ESP_OK: v_ref successfully routed to selected GPIO
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
*/
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio);
/**
* @brief Output ADC2 reference voltage to ``adc2_channe_t``'s IO.
*
* 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.
*
* @deprecated Use ``adc_vref_to_gpio`` instead.
*
* @param[in] gpio GPIO number (ADC2's channels are supported)
*
* @return
* - ESP_OK: v_ref successfully routed to selected GPIO
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
*/
esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) __attribute__((deprecated));
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
//These APIs are only supported on ESP32 and ESP32-S2. On ESP32-C3 and later chips, please use ``adc_digi_initialize`` and ``adc_digi_deinitialize``
/**
* @brief ADC digital controller initialization.
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_init(void);
/**
* @brief ADC digital controller deinitialization.
* @return
* - ESP_OK Success
*/
esp_err_t adc_digi_deinit(void);
#endif
/**
* @brief Setting the digital controller.
*
* @param config Pointer to digital controller paramter. Refer to ``adc_digi_config_t``.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_controller_config(const adc_digi_config_t *config);
#if CONFIG_IDF_TARGET_ESP32C3
//This feature is currently supported on ESP32C3, will be supported on other chips soon
/*---------------------------------------------------------------
DMA setting
---------------------------------------------------------------*/
/**
* @brief Initialize the Digital ADC.
*
* @param init_config Pointer to Digital ADC initilization config. Refer to ``adc_digi_init_config_t``.
*
* @return
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* - ESP_ERR_NO_MEM If out of memory
* - ESP_OK On success
*/
esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config);
/**
* @brief Start the Digital ADC and DMA peripherals. After this, the hardware starts working.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_start(void);
/**
* @brief Stop the Digital ADC and DMA peripherals. After this, the hardware stops working.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_stop(void);
/**
* @brief Read bytes from Digital ADC through DMA.
*
* @param[out] buf Buffer to read from ADC.
* @param[in] length_max Expected length of data read from the ADC.
* @param[out] out_length Real length of data read from the ADC via this API.
* @param[in] timeout_ms Time to wait for data via this API, in millisecond.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate.
* - ESP_ERR_TIMEOUT Operation timed out
* - ESP_OK On success
*/
esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms);
/**
* @brief Deinitialize the Digital ADC.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_deinitialize(void);
#endif //#if CONFIG_IDF_TARGET_ESP32C3
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,74 @@
// Copyright 2015-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
#ifdef __cplusplus
extern "C" {
#endif
#warning driver/can.h is deprecated, please use driver/twai.h instead
#include "hal/can_types.h"
#include "driver/twai.h"
/* ---------------------------- Compatibility ------------------------------- */
#define CAN_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode) TWAI_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode)
#define CAN_ALERT_TX_IDLE TWAI_ALERT_TX_IDLE
#define CAN_ALERT_TX_SUCCESS TWAI_ALERT_TX_SUCCESS
#define CAN_ALERT_BELOW_ERR_WARN TWAI_ALERT_BELOW_ERR_WARN
#define CAN_ALERT_ERR_ACTIVE TWAI_ALERT_ERR_ACTIVE
#define CAN_ALERT_RECOVERY_IN_PROGRESS TWAI_ALERT_RECOVERY_IN_PROGRESS
#define CAN_ALERT_BUS_RECOVERED TWAI_ALERT_BUS_RECOVERED
#define CAN_ALERT_ARB_LOST TWAI_ALERT_ARB_LOST
#define CAN_ALERT_ABOVE_ERR_WARN TWAI_ALERT_ABOVE_ERR_WARN
#define CAN_ALERT_BUS_ERROR TWAI_ALERT_BUS_ERROR
#define CAN_ALERT_TX_FAILED TWAI_ALERT_TX_FAILED
#define CAN_ALERT_RX_QUEUE_FULL TWAI_ALERT_RX_QUEUE_FULL
#define CAN_ALERT_ERR_PASS TWAI_ALERT_ERR_PASS
#define CAN_ALERT_BUS_OFF TWAI_ALERT_BUS_OFF
#define CAN_ALERT_ALL TWAI_ALERT_ALL
#define CAN_ALERT_NONE TWAI_ALERT_NONE
#define CAN_ALERT_AND_LOG TWAI_ALERT_AND_LOG
#define CAN_IO_UNUSED TWAI_IO_UNUSED
#define CAN_STATE_STOPPED TWAI_STATE_STOPPED
#define CAN_STATE_RUNNING TWAI_STATE_RUNNING
#define CAN_STATE_BUS_OFF TWAI_STATE_BUS_OFF
#define CAN_STATE_RECOVERING TWAI_STATE_RECOVERING
typedef twai_state_t can_state_t;
typedef twai_general_config_t can_general_config_t;
typedef twai_status_info_t can_status_info_t;
#define can_driver_install(g_config, t_config, f_config) twai_driver_install(g_config, t_config, f_config)
#define can_driver_uninstall() twai_driver_uninstall()
#define can_start() twai_start()
#define can_stop() twai_stop()
#define can_transmit(message, ticks_to_wait) twai_transmit(message, ticks_to_wait)
#define can_receive(message, ticks_to_wait) twai_receive(message, ticks_to_wait)
#define can_read_alerts(alerts, ticks_to_wait) twai_read_alerts(alerts, ticks_to_wait)
#define can_reconfigure_alerts(alerts_enabled, current_alerts) twai_reconfigure_alerts(alerts_enabled, current_alerts)
#define can_initiate_recovery() twai_initiate_recovery()
#define can_get_status_info(status_info) twai_get_status_info(status_info)
#define can_clear_transmit_queue() twai_clear_transmit_queue()
#define can_clear_receive_queue() twai_clear_receive_queue()
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,98 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 "esp_err.h"
#include "driver/gpio.h"
#include "hal/dac_types.h"
/**
* @brief Get the GPIO number of a specific DAC channel.
*
* @param channel Channel to get the gpio number
* @param gpio_num output buffer to hold the gpio number
* @return
* - ESP_OK if success
*/
esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Set DAC output voltage.
* DAC output is 8-bit. Maximum (255) corresponds to VDD3P3_RTC.
*
* @note Need to configure DAC pad before calling this function.
* DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26
* @param channel DAC channel
* @param dac_value DAC output value
*
* @return
* - ESP_OK success
*/
esp_err_t dac_output_voltage(dac_channel_t channel, uint8_t dac_value);
/**
* @brief DAC pad output enable
*
* @param channel DAC channel
* @note DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26
* I2S left channel will be mapped to DAC channel 2
* I2S right channel will be mapped to DAC channel 1
*/
esp_err_t dac_output_enable(dac_channel_t channel);
/**
* @brief DAC pad output disable
*
* @param channel DAC channel
* @note DAC channel 1 is attached to GPIO25, DAC channel 2 is attached to GPIO26
* @return
* - ESP_OK success
*/
esp_err_t dac_output_disable(dac_channel_t channel);
/**
* @brief Enable cosine wave generator output.
*
* @return
* - ESP_OK success
*/
esp_err_t dac_cw_generator_enable(void);
/**
* @brief Disable cosine wave generator output.
*
* @return
* - ESP_OK success
*/
esp_err_t dac_cw_generator_disable(void);
/**
* @brief Config the cosine wave generator function in DAC module.
*
* @param cw Configuration.
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG The parameter is NULL.
*/
esp_err_t dac_cw_generator_config(dac_cw_config_t *cw);
#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 <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp_attr.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of Dedicated GPIO bundle
*/
typedef struct dedic_gpio_bundle_t *dedic_gpio_bundle_handle_t;
/**
* @brief Type of Dedicated GPIO bundle configuration
*/
typedef struct {
const int *gpio_array; /*!< Array of GPIO numbers, gpio_array[0] ~ gpio_array[size-1] <=> low_dedic_channel_num ~ high_dedic_channel_num */
size_t array_size; /*!< Number of GPIOs in gpio_array */
struct {
int in_en: 1; /*!< Enable input */
int in_invert: 1; /*!< Invert input signal */
int out_en: 1; /*!< Enable output */
int out_invert: 1; /*!< Invert output signal */
} flags; /*!< Flags to control specific behaviour of GPIO bundle */
} dedic_gpio_bundle_config_t;
/**
* @brief Create GPIO bundle and return the handle
*
* @param[in] config Configuration of GPIO bundle
* @param[out] ret_bundle Returned handle of the new created GPIO bundle
* @return
* - ESP_OK: Create GPIO bundle successfully
* - ESP_ERR_INVALID_ARG: Create GPIO bundle failed because of invalid argument
* - ESP_ERR_NO_MEM: Create GPIO bundle failed because of no capable memory
* - ESP_ERR_NOT_FOUND: Create GPIO bundle failed because of no enough continuous dedicated channels
* - ESP_FAIL: Create GPIO bundle failed because of other error
*
* @note One has to enable at least input or output mode in "config" parameter.
*/
esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_gpio_bundle_handle_t *ret_bundle);
/**
* @brief Destory GPIO bundle
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @return
* - ESP_OK: Destory GPIO bundle successfully
* - ESP_ERR_INVALID_ARG: Destory GPIO bundle failed because of invalid argument
* - ESP_FAIL: Destory GPIO bundle failed because of other error
*/
esp_err_t dedic_gpio_del_bundle(dedic_gpio_bundle_handle_t bundle);
/**@{*/
/**
* @brief Get allocated channel mask
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @param[out] mask Returned mask value for on specific direction (in or out)
* @return
* - ESP_OK: Get channel mask successfully
* - ESP_ERR_INVALID_ARG: Get channel mask failed because of invalid argument
* - ESP_FAIL: Get channel mask failed because of other error
*
* @note Each bundle should have at least one mask (in or/and out), based on bundle configuration.
* @note With the returned mask, user can directly invoke LL function like "cpu_ll_write_dedic_gpio_mask"
* or write assembly code with dedicated GPIO instructions, to get better performance on GPIO manipulation.
*/
esp_err_t dedic_gpio_get_out_mask(dedic_gpio_bundle_handle_t bundle, uint32_t *mask);
esp_err_t dedic_gpio_get_in_mask(dedic_gpio_bundle_handle_t bundle, uint32_t *mask);
/**@}*/
/**
* @brief Write value to GPIO bundle
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @param[in] mask Mask of the GPIOs to be written in the given bundle
* @param[in] value Value to write to given GPIO bundle, low bit represents low member in the bundle
*
* @note The mask is seen from the view of GPIO bundle.
* For example, bundleA contains [GPIO10, GPIO12, GPIO17], to set GPIO17 individually, the mask should be 0x04.
* @note For performance reasons, this function doesn't check the validity of any parameters, and is placed in IRAM.
*/
void dedic_gpio_bundle_write(dedic_gpio_bundle_handle_t bundle, uint32_t mask, uint32_t value) IRAM_ATTR;
/**
* @brief Read the value that output from the given GPIO bundle
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @return Value that output from the GPIO bundle, low bit represents low member in the bundle
*
* @note For performance reasons, this function doesn't check the validity of any parameters, and is placed in IRAM.
*/
uint32_t dedic_gpio_bundle_read_out(dedic_gpio_bundle_handle_t bundle) IRAM_ATTR;
/**
* @brief Read the value that input to the given GPIO bundle
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @return Value that input to the GPIO bundle, low bit represents low member in the bundle
*
* @note For performance reasons, this function doesn't check the validity of any parameters, and is placed in IRAM.
*/
uint32_t dedic_gpio_bundle_read_in(dedic_gpio_bundle_handle_t bundle) IRAM_ATTR;
#if SOC_DEDIC_GPIO_HAS_INTERRUPT
/**
* @brief Supported type of dedicated GPIO interrupt
*/
typedef enum {
DEDIC_GPIO_INTR_NONE, /*!< No interrupt */
DEDIC_GPIO_INTR_LOW_LEVEL = 2, /*!< Interrupt on low level */
DEDIC_GPIO_INTR_HIGH_LEVEL, /*!< Interrupt on high level */
DEDIC_GPIO_INTR_NEG_EDGE, /*!< Interrupt on negedge */
DEDIC_GPIO_INTR_POS_EDGE, /*!< Interrupt on posedge */
DEDIC_GPIO_INTR_BOTH_EDGE /*!< Interrupt on both negedge and posedge */
} dedic_gpio_intr_type_t;
/**
* @brief Type of dedicated GPIO ISR callback function
*
* @param bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @param index Index of the GPIO in its corresponding bundle (count from 0)
* @param args User defined arguments for the callback function. It's passed through `dedic_gpio_bundle_set_interrupt_and_callback`
* @return If a high priority task is woken up by the callback function
*/
typedef bool (*dedic_gpio_isr_callback_t)(dedic_gpio_bundle_handle_t bundle, uint32_t index, void *args);
/**
* @brief Set interrupt and callback function for GPIO bundle
*
* @param[in] bundle Handle of GPIO bundle that returned from "dedic_gpio_new_bundle"
* @param[in] mask Mask of the GPIOs in the given bundle
* @param[in] intr_type Interrupt type, set to DEDIC_GPIO_INTR_NONE can disable interrupt
* @param[in] cb_isr Callback function, which got invoked in ISR context. A NULL pointer here will bypass the callback
* @param[in] cb_args User defined argument to be passed to the callback function
*
* @note This function is only valid for bundle with input mode enabled. See "dedic_gpio_bundle_config_t"
* @note The mask is seen from the view of GPIO Bundle.
* For example, bundleA contains [GPIO10, GPIO12, GPIO17], to set GPIO17 individually, the mask should be 0x04.
*
* @return
* - ESP_OK: Set GPIO interrupt and callback function successfully
* - ESP_ERR_INVALID_ARG: Set GPIO interrupt and callback function failed because of invalid argument
* - ESP_FAIL: Set GPIO interrupt and callback function failed because of other error
*/
esp_err_t dedic_gpio_bundle_set_interrupt_and_callback(dedic_gpio_bundle_handle_t bundle, uint32_t mask, dedic_gpio_intr_type_t intr_type, dedic_gpio_isr_callback_t cb_isr, void *cb_args);
#endif // SOC_DEDIC_GPIO_HAS_INTERRUPT
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,555 @@
// 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 "sdkconfig.h"
#include "esp_err.h"
#include <esp_types.h>
#include <esp_bit_defs.h>
#include "esp_attr.h"
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
#include "soc/gpio_periph.h"
#include "hal/gpio_types.h"
// |================================= WARNING ====================================================== |
// | Including ROM header file in a PUBLIC API file will be REMOVED in the next major release (5.x). |
// | User should include "esp_rom_gpio.h" in their code if they have to use those ROM API. |
// |================================================================================================ |
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/gpio.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/gpio.h"
#endif
#ifdef CONFIG_LEGACY_INCLUDE_COMMON_HEADERS
#include "soc/rtc_io_reg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define GPIO_PIN_COUNT (SOC_GPIO_PIN_COUNT)
/// Check whether it is a valid GPIO number
#define GPIO_IS_VALID_GPIO(gpio_num) (((1ULL << (gpio_num)) & SOC_GPIO_VALID_GPIO_MASK) != 0)
/// Check whether it can be a valid GPIO number of output mode
#define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) (((1ULL << (gpio_num)) & SOC_GPIO_VALID_OUTPUT_GPIO_MASK) != 0)
typedef intr_handle_t gpio_isr_handle_t;
/**
* @brief GPIO common configuration
*
* Configure GPIO's Mode,pull-up,PullDown,IntrType
*
* @param pGPIOConfig Pointer to GPIO configure struct
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*
*/
esp_err_t gpio_config(const gpio_config_t *pGPIOConfig);
/**
* @brief Reset an gpio to default state (select gpio function, enable pullup and disable input and output).
*
* @param gpio_num GPIO number.
*
* @note This function also configures the IOMUX for this pin to the GPIO
* function, and disconnects any other peripheral output configured via GPIO
* Matrix.
*
* @return Always return ESP_OK.
*/
esp_err_t gpio_reset_pin(gpio_num_t gpio_num);
/**
* @brief GPIO set interrupt trigger type
*
* @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
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*
*/
esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/**
* @brief Enable GPIO module interrupt signal
*
* @note Please do not use the interrupt of GPIO36 and GPIO39 when using ADC or Wi-Fi with sleep mode enabled.
* Please refer to the comments of `adc1_get_raw`.
* Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue.
* As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA),
* but will remove the glitches on GPIO36 and GPIO39.
*
* @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*
*/
esp_err_t gpio_intr_enable(gpio_num_t gpio_num);
/**
* @brief Disable GPIO module interrupt signal
*
* @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*
*/
esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
/**
* @brief GPIO set output level
*
* @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
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO number error
*
*/
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t 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 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
*
*/
int gpio_get_level(gpio_num_t gpio_num);
/**
* @brief GPIO set direction
*
* Configure GPIO direction,such as output_only,input_only,output_and_input
*
* @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO error
*
*/
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
/**
* @brief Configure GPIO pull-up/pull-down resistors
*
* Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not.
*
* @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param pull GPIO pull up/down mode.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG : Parameter error
*
*/
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
/**
* @brief Enable GPIO wake-up function.
*
* @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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/**
* @brief Disable GPIO wake-up function.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
/**
* @brief Register GPIO interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* This ISR function is called whenever any GPIO interrupt occurs. See
* the alternative gpio_install_isr_service() and
* gpio_isr_handler_add() API in order to have the driver support
* per-GPIO ISRs.
*
* @param fn Interrupt handler function.
* @param 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.
* @param arg Parameter for handler function
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will be returned here.
*
* \verbatim embed:rst:leading-asterisk
* To disable or remove the ISR, pass the returned handle to the :doc:`interrupt allocation functions </api-reference/system/intr_alloc>`.
* \endverbatim
*
* @return
* - ESP_OK Success ;
* - ESP_ERR_INVALID_ARG GPIO error
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
*/
esp_err_t gpio_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, gpio_isr_handle_t *handle);
/**
* @brief Enable pull-up on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pullup_en(gpio_num_t gpio_num);
/**
* @brief Disable pull-up on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pullup_dis(gpio_num_t gpio_num);
/**
* @brief Enable pull-down on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
/**
* @brief Disable pull-down on GPIO.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
/**
* @brief Install the driver's GPIO ISR handler service, which allows per-pin GPIO interrupt handlers.
*
* This function is incompatible with gpio_isr_register() - if that function is used, a single global ISR is registered for all GPIO interrupts. If this function is used, the ISR service provides a global GPIO ISR and individual pin handlers are registered via the gpio_isr_handler_add() function.
*
* @param 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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_NO_MEM No memory to install this service
* - ESP_ERR_INVALID_STATE ISR service already installed.
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* - ESP_ERR_INVALID_ARG GPIO error
*/
esp_err_t gpio_install_isr_service(int intr_alloc_flags);
/**
* @brief Uninstall the driver's GPIO ISR service, freeing related resources.
*/
void gpio_uninstall_isr_service(void);
/**
* @brief Add ISR handler for the corresponding GPIO pin.
*
* Call this function after using gpio_install_isr_service() to
* install the driver's GPIO ISR handler service.
*
* The pin ISR handlers no longer need to be declared with IRAM_ATTR,
* unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
* ISR in gpio_install_isr_service().
*
* This ISR handler will be called from an ISR. So there is a stack
* size limit (configurable as "ISR stack size" in menuconfig). This
* limit is smaller compared to a global GPIO interrupt handler due
* to the additional level of indirection.
*
* @param gpio_num GPIO number
* @param isr_handler ISR handler function for the corresponding GPIO number.
* @param args parameter for ISR handler.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args);
/**
* @brief Remove ISR handler for the corresponding GPIO pin.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Wrong state, the ISR service has not been initialized.
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_isr_handler_remove(gpio_num_t gpio_num);
/**
* @brief Set GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t strength);
/**
* @brief Get GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Pointer to accept drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t *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 gpio_num GPIO number, only support output-capable GPIOs
*
* @return
* - ESP_OK Success
* - ESP_ERR_NOT_SUPPORTED Not support pad hold function
*/
esp_err_t gpio_hold_en(gpio_num_t 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 gpio_num GPIO number, only support output-capable GPIOs
*
* @return
* - ESP_OK Success
* - ESP_ERR_NOT_SUPPORTED Not support pad hold function
*/
esp_err_t gpio_hold_dis(gpio_num_t 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.
*/
void gpio_deep_sleep_hold_en(void);
/**
* @brief Disable all digital gpio pad hold function during Deep-sleep.
*
*/
void gpio_deep_sleep_hold_dis(void);
/**
* @brief Set pad input to a peripheral signal through the IOMUX.
* @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``.
*/
void gpio_iomux_in(uint32_t gpio_num, uint32_t signal_idx);
/**
* @brief Set peripheral output to an GPIO pad through the IOMUX.
* @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.
*/
void gpio_iomux_out(uint8_t gpio_num, int func, bool 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.
* */
esp_err_t gpio_force_hold_all(void);
/**
* @brief Force unhold digital and rtc gpio pad.
* @note GPIO force unhold, whether the chip in sleep mode or wakeup mode.
* */
esp_err_t gpio_force_unhold_all(void);
#endif
#if SOC_GPIO_SUPPORT_SLP_SWITCH
/**
* @brief Enable SLP_SEL to change GPIO status automantically in lightsleep.
* @param gpio_num GPIO number of the pad.
*
* @return
* - ESP_OK Success
*
*/
esp_err_t gpio_sleep_sel_en(gpio_num_t gpio_num);
/**
* @brief Disable SLP_SEL to change GPIO status automantically in lightsleep.
* @param gpio_num GPIO number of the pad.
*
* @return
* - ESP_OK Success
*/
esp_err_t gpio_sleep_sel_dis(gpio_num_t gpio_num);
/**
* @brief GPIO set direction at sleep
*
* Configure GPIO direction,such as output_only,input_only,output_and_input
*
* @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO error
*/
esp_err_t gpio_sleep_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
/**
* @brief Configure GPIO pull-up/pull-down resistors at sleep
*
* Only pins that support both input & output have integrated pull-up and pull-down resistors. Input-only GPIOs 34-39 do not.
*
* @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
* @param pull GPIO pull up/down mode.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG : Parameter error
*/
esp_err_t gpio_sleep_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
#if CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL
/**
* @brief Emulate ESP32S2 behaviour to backup FUN_PU, FUN_PD information
*
* @note Need to be called before sleep.
*
* @return
* - ESP_OK Success
*/
esp_err_t gpio_sleep_pupd_config_apply(gpio_num_t gpio_num);
/**
* @brief Emulate ESP32S2 behaviour to restore FUN_PU, FUN_PD information
*
* @note Need to be called after sleep.
*
* @return
* - ESP_OK Success
*/
esp_err_t gpio_sleep_pupd_config_unapply(gpio_num_t gpio_num);
#endif
#endif
#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP
#define GPIO_IS_DEEP_SLEEP_WAKEUP_VALID_GPIO(gpio_num) ((gpio_num & ~SOC_GPIO_DEEP_SLEEP_WAKEUP_VALID_GPIO_MASK) == 0)
/**
* @brief Enable GPIO deep-sleep wake-up function.
*
* @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.
*
* @note Called by the SDK. User shouldn't call this directly in the APP.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/**
* @brief Disable GPIO deep-sleep wake-up function.
*
* @param gpio_num GPIO number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t gpio_deep_sleep_wakeup_disable(gpio_num_t gpio_num);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,519 @@
// 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.
#ifndef _DRIVER_I2C_H_
#define _DRIVER_I2C_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_types.h>
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "hal/i2c_types.h"
#define I2C_APB_CLK_FREQ APB_CLK_FREQ /*!< I2C source clock is APB clock, 80MHz */
#define I2C_NUM_0 (0) /*!< I2C port 0 */
#define I2C_NUM_1 (1) /*!< I2C port 1 */
#define I2C_NUM_MAX (SOC_I2C_NUM) /*!< I2C port max */
typedef void *i2c_cmd_handle_t; /*!< I2C command handle */
/**
* @brief I2C driver install
*
* @param i2c_num I2C port number
* @param mode I2C mode( master or slave )
* @param slv_rx_buf_len receiving buffer size for slave mode
* @note
* Only slave mode will use this value, driver will ignore this value in master mode.
* @param slv_tx_buf_len sending buffer size for slave mode
* @note
* Only slave mode will use this value, driver will ignore this value in master mode.
* @param 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.
* @note
* In master mode, if the cache is likely to be disabled(such as write flash) and the slave is time-sensitive,
* `ESP_INTR_FLAG_IRAM` is suggested to be used. In this case, please use the memory allocated from internal RAM in i2c read and write function,
* because we can not access the psram(if psram is enabled) in interrupt handle function when cache is disabled.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Driver install error
*/
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags);
/**
* @brief I2C driver delete
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_driver_delete(i2c_port_t i2c_num);
/**
* @brief I2C parameter initialization
*
* @param i2c_num I2C port number
* @param i2c_conf pointer to I2C parameter settings
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf);
/**
* @brief reset I2C tx hardware fifo
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_reset_tx_fifo(i2c_port_t i2c_num);
/**
* @brief reset I2C rx fifo
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_reset_rx_fifo(i2c_port_t i2c_num);
/**
* @brief I2C isr handler register
*
* @param i2c_num I2C port number
* @param fn isr handler function
* @param arg parameter for isr handler function
* @param 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.
* @param handle handle return from esp_intr_alloc.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_isr_register(i2c_port_t i2c_num, void (*fn)(void *), void *arg, int intr_alloc_flags, intr_handle_t *handle);
/**
* @brief to delete and free I2C isr.
*
* @param handle handle of isr.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_isr_free(intr_handle_t handle);
/**
* @brief Configure GPIO signal for I2C sck and sda
*
* @param i2c_num I2C port number
* @param sda_io_num GPIO number for I2C sda signal
* @param scl_io_num GPIO number for I2C scl signal
* @param sda_pullup_en Whether to enable the internal pullup for sda pin
* @param scl_pullup_en Whether to enable the internal pullup for scl pin
* @param mode I2C mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num,
bool sda_pullup_en, bool scl_pullup_en, i2c_mode_t mode);
/**
* @brief Create and init I2C command link
* @note
* Before we build I2C command link, we need to call i2c_cmd_link_create() to create
* a command link.
* After we finish sending the commands, we need to call i2c_cmd_link_delete() to
* release and return the resources.
*
* @return i2c command link handler
*/
i2c_cmd_handle_t i2c_cmd_link_create(void);
/**
* @brief Free I2C command link
* @note
* Before we build I2C command link, we need to call i2c_cmd_link_create() to create
* a command link.
* After we finish sending the commands, we need to call i2c_cmd_link_delete() to
* release and return the resources.
*
* @param cmd_handle I2C command handle
*/
void i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle);
/**
* @brief Queue command for I2C master to generate a start signal
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle);
/**
* @brief Queue command for I2C master to write one byte to I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data I2C one byte command to write to bus
* @param ack_en enable ack check for master
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en);
/**
* @brief Queue command for I2C master to write buffer to I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data data to send
* @note
* If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.
* @param data_len data length
* @param ack_en enable ack check for master
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, const uint8_t *data, size_t data_len, bool ack_en);
/**
* @brief Queue command for I2C master to read one byte from I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data pointer accept the data byte
* @note
* If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.
* @param ack ack value for read command
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t *data, i2c_ack_type_t ack);
/**
* @brief Queue command for I2C master to read data from I2C bus
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
* @param data data buffer to accept the data from bus
* @note
* If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.
* @param data_len read data length
* @param ack ack value for read command
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t *data, size_t data_len, i2c_ack_type_t ack);
/**
* @brief Queue command for I2C master to generate a stop signal
* @note
* Only call this function in I2C master mode
* Call i2c_master_cmd_begin() to send all queued commands
*
* @param cmd_handle I2C cmd link
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle);
/**
* @brief I2C master send queued commands.
* This function will trigger sending all queued commands.
* The task will be blocked until all the commands have been sent out.
* The I2C APIs are not thread-safe, if you want to use one I2C port in different tasks,
* you need to take care of the multi-thread issue.
* @note
* Only call this function in I2C master mode
*
* @param i2c_num I2C port number
* @param cmd_handle I2C command handler
* @param ticks_to_wait maximum wait ticks.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Sending command error, slave doesn't ACK the transfer.
* - ESP_ERR_INVALID_STATE I2C driver not installed or not in master mode.
* - ESP_ERR_TIMEOUT Operation timeout because the bus is busy.
*/
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait);
/**
* @brief I2C slave write data to internal ringbuffer, when tx fifo empty, isr will fill the hardware
* fifo from the internal ringbuffer
* @note
* Only call this function in I2C slave mode
*
* @param i2c_num I2C port number
* @param data data pointer to write into internal buffer
* @param size data size
* @param ticks_to_wait Maximum waiting ticks
*
* @return
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that pushed to the I2C slave buffer.
*/
int i2c_slave_write_buffer(i2c_port_t i2c_num, const uint8_t *data, int size, TickType_t ticks_to_wait);
/**
* @brief I2C slave read data from internal buffer. When I2C slave receive data, isr will copy received data
* from hardware rx fifo to internal ringbuffer. Then users can read from internal ringbuffer.
* @note
* Only call this function in I2C slave mode
*
* @param i2c_num I2C port number
* @param data data pointer to accept data from internal buffer
* @param max_size Maximum data size to read
* @param ticks_to_wait Maximum waiting ticks
*
* @return
* - ESP_FAIL(-1) Parameter error
* - Others(>=0) The number of data bytes that read from I2C slave buffer.
*/
int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t *data, size_t max_size, TickType_t ticks_to_wait);
/**
* @brief set I2C master clock period
*
* @param i2c_num I2C port number
* @param high_period clock cycle number during SCL is high level, high_period is a 14 bit value
* @param low_period clock cycle number during SCL is low level, low_period is a 14 bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_period(i2c_port_t i2c_num, int high_period, int low_period);
/**
* @brief get I2C master clock period
*
* @param i2c_num I2C port number
* @param high_period pointer to get clock cycle number during SCL is high level, will get a 14 bit value
* @param low_period pointer to get clock cycle number during SCL is low level, will get a 14 bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_period(i2c_port_t i2c_num, int *high_period, int *low_period);
/**
* @brief enable hardware filter on I2C bus
* Sometimes the I2C bus is disturbed by high frequency noise(about 20ns), or the rising edge of
* the SCL clock is very slow, these may cause the master state machine broken. enable hardware
* filter can filter out high frequency interference and make the master more stable.
* @note
* Enable filter will slow the SCL clock.
*
* @param i2c_num I2C port number
* @param cyc_num the APB cycles need to be filtered(0<= cyc_num <=7).
* When the period of a pulse is less than cyc_num * APB_cycle, the I2C controller will ignore this pulse.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_filter_enable(i2c_port_t i2c_num, uint8_t cyc_num);
/**
* @brief disable filter on I2C bus
*
* @param i2c_num I2C port number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_filter_disable(i2c_port_t i2c_num);
/**
* @brief set I2C master start signal timing
*
* @param i2c_num I2C port number
* @param setup_time clock number between the falling-edge of SDA and rising-edge of SCL for start mark, it's a 10-bit value.
* @param hold_time clock num between the falling-edge of SDA and falling-edge of SCL for start mark, it's a 10-bit value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
/**
* @brief get I2C master start signal timing
*
* @param i2c_num I2C port number
* @param setup_time pointer to get setup time
* @param hold_time pointer to get hold time
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_start_timing(i2c_port_t i2c_num, int *setup_time, int *hold_time);
/**
* @brief set I2C master stop signal timing
*
* @param i2c_num I2C port number
* @param setup_time clock num between the rising-edge of SCL and the rising-edge of SDA, it's a 10-bit value.
* @param hold_time clock number after the STOP bit's rising-edge, it's a 14-bit value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time);
/**
* @brief get I2C master stop signal timing
*
* @param i2c_num I2C port number
* @param setup_time pointer to get setup time.
* @param hold_time pointer to get hold time.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_stop_timing(i2c_port_t i2c_num, int *setup_time, int *hold_time);
/**
* @brief set I2C data signal timing
*
* @param i2c_num I2C port number
* @param sample_time clock number I2C used to sample data on SDA after the rising-edge of SCL, it's a 10-bit value
* @param hold_time clock number I2C used to hold the data after the falling-edge of SCL, it's a 10-bit value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time);
/**
* @brief get I2C data signal timing
*
* @param i2c_num I2C port number
* @param sample_time pointer to get sample time
* @param hold_time pointer to get hold time
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int *sample_time, int *hold_time);
/**
* @brief set I2C timeout value
* @param i2c_num I2C port number
* @param timeout timeout value for I2C bus (unit: APB 80Mhz clock cycle)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout);
/**
* @brief get I2C timeout value
* @param i2c_num I2C port number
* @param timeout pointer to get timeout value
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_timeout(i2c_port_t i2c_num, int *timeout);
/**
* @brief set I2C data transfer mode
*
* @param i2c_num I2C port number
* @param tx_trans_mode I2C sending data mode
* @param rx_trans_mode I2C receving data mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_set_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t tx_trans_mode, i2c_trans_mode_t rx_trans_mode);
/**
* @brief get I2C data transfer mode
*
* @param i2c_num I2C port number
* @param tx_trans_mode pointer to get I2C sending data mode
* @param rx_trans_mode pointer to get I2C receiving data mode
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2c_get_data_mode(i2c_port_t i2c_num, i2c_trans_mode_t *tx_trans_mode, i2c_trans_mode_t *rx_trans_mode);
#ifdef __cplusplus
}
#endif
#endif /*_DRIVER_I2C_H_*/

View File

@ -0,0 +1,338 @@
// 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 "esp_types.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "soc/i2s_periph.h"
#include "soc/rtc_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#if SOC_I2S_SUPPORTS_ADC_DAC
#include "driver/adc.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
*
* @note
* The I2S peripheral output signals can be connected to multiple GPIO pads.
* However, the I2S peripheral input signal can only be connected to one GPIO pad.
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)
*
* Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where
* the current configuration should not be changed.
*
* @note if *pin is set as NULL, this function will initialize both of the built-in DAC channels by default.
* if you don't want this to happen and you want to initialize only one of the DAC channels, you can call i2s_set_dac_mode instead.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL IO error
*/
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief Set PDM mode down-sample rate
* In PDM RX mode, there would be 2 rounds of downsample process in hardware.
* In the first downsample process, the sampling number can be 16 or 8.
* In the second downsample process, the sampling number is fixed as 8.
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly.
* @param i2s_num I2S_NUM_0, I2S_NUM_1
* @param dsr i2s RX down sample rate for PDM mode.
*
* @note After calling this function, it would call i2s_set_clk inside to update the clock frequency.
* Please call this function after I2S driver has been initialized.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
#endif
/**
* @brief Set I2S dac mode, I2S built-in DAC is disabled by default
*
* @param dac_mode DAC mode configurations - see i2s_dac_mode_t
*
* @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip.
* If either of the built-in DAC channel are enabled, the other one can not
* be used as RTC DAC function at the same time.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode);
/**
* @brief Install and start I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
*
* This function must be called before any I2S driver read/write operations.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
/**
* @brief Uninstall I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
/**
* @brief Write data to I2S DMA transmit buffer.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);
/**
* @brief Write data to I2S DMA transmit buffer while expanding the number of bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param src_bits Source audio bit
*
* @param aim_bits Bit wanted, no more than 32, and must be greater than src_bits
*
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* Format of the data in source buffer is determined by the I2S
* configuration (see i2s_config_t).
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait);
/**
* @brief Read data from I2S DMA receive buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest Destination address to read into
*
* @param size Size of data in bytes
*
* @param[out] bytes_read Number of bytes read, if timeout, bytes read will be less than the size passed in.
*
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
*
* @note If the built-in ADC mode is enabled, we should call i2s_adc_enable and i2s_adc_disable around the whole reading process,
* to prevent the data getting corrupted.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);
/**
* @brief Set sample rate used for I2S RX and TX.
*
* The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample).
*
* `bit_clock = rate * (number of channels) * bits_per_sample`
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Stop I2S driver
*
* There is no need to call i2s_stop() before calling i2s_driver_uninstall().
*
* Disables I2S TX/RX, until i2s_start() is called.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_stop(i2s_port_t i2s_num);
/**
* @brief Start I2S driver
*
* It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().
*
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_start(i2s_port_t i2s_num);
/**
* @brief Zero the contents of the TX DMA buffer.
*
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num);
/**
* @brief Set clock & bit width used for I2S RX and TX.
*
* Similar to i2s_set_sample_rates(), but also sets bit width.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
*
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
/**
* @brief get clock set on particular port number.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - actual clock set by i2s driver
*/
float i2s_get_clk(i2s_port_t i2s_num);
#if SOC_I2S_SUPPORTS_ADC_DAC
/**
* @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad,
* and set ADC parameters.
* @note In this mode, the ADC maximum sampling rate is 150KHz. Set the sampling rate through ``i2s_config_t``.
* @param adc_unit SAR ADC unit index
* @param adc_channel ADC channel index
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_set_adc_mode(adc_unit_t adc_unit, adc1_channel_t adc_channel);
/**
* @brief Start to use I2S built-in ADC mode
* @note This function would acquire the lock of ADC to prevent the data getting corrupted
* during the I2S peripheral is being used to do fully continuous ADC sampling.
*
* @param i2s_num i2s port index
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver state error
*/
esp_err_t i2s_adc_enable(i2s_port_t i2s_num);
/**
* @brief Stop to use I2S built-in ADC mode
* @param i2s_num i2s port index
* @note This function would release the lock of ADC so that other tasks can use ADC.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver state error
*/
esp_err_t i2s_adc_disable(i2s_port_t i2s_num);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,423 @@
// 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_err.h"
#include "esp_intr_alloc.h"
#include "soc/soc.h"
#include "hal/ledc_types.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
#define LEDC_REF_CLK_HZ (REF_CLK_FREQ)
#define LEDC_ERR_DUTY (0xFFFFFFFF)
#define LEDC_ERR_VAL (-1)
typedef intr_handle_t ledc_isr_handle_t;
/**
* @brief LEDC channel configuration
* Configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC duty resolution
*
* @param ledc_conf Pointer of LEDC channel configure struct
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_channel_config(const ledc_channel_config_t* ledc_conf);
/**
* @brief LEDC timer configuration
* Configure LEDC timer with the given source timer/frequency(Hz)/duty_resolution
*
* @param timer_conf Pointer of LEDC timer configure struct
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current duty_resolution.
*/
esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf);
/**
* @brief LEDC update channel parameters
* @note Call this function to activate the LEDC updated parameters.
* After ledc_set_duty, we need to call this function to update the settings.
* @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to
* control one LEDC channel in different tasks at the same time.
* A thread-safe version of API is ledc_set_duty_and_update
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*
*/
esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
/**
* @brief Set LEDC output gpio.
*
* @param gpio_num The LEDC output gpio
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param ledc_channel LEDC channel (0-7), select from ledc_channel_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel);
/**
* @brief LEDC stop.
* Disable LEDC output, and set idle level
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param idle_level Set output idle level after LEDC stops.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
/**
* @brief LEDC set channel frequency (Hz)
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_num LEDC timer index (0-3), select from ledc_timer_t
* @param freq_hz Set the LEDC frequency
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current duty_resolution.
*/
esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz);
/**
* @brief LEDC get channel frequency (Hz)
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_num LEDC timer index (0-3), select from ledc_timer_t
*
* @return
* - 0 error
* - Others Current LEDC frequency
*/
uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
/**
* @brief LEDC set duty and hpoint value
* Only after calling ledc_update_duty will the duty update.
* @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to
* control one LEDC channel in different tasks at the same time.
* A thread-safe version of API is ledc_set_duty_and_update
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_set_duty_with_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, uint32_t hpoint);
/**
* @brief LEDC get hpoint value, the counter value when the output is set high level.
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @return
* - LEDC_ERR_VAL if parameter error
* - Others Current hpoint value of LEDC channel
*/
int ledc_get_hpoint(ledc_mode_t speed_mode, ledc_channel_t channel);
/**
* @brief LEDC set duty
* This function do not change the hpoint value of this channel. if needed, please call ledc_set_duty_with_hpoint.
* only after calling ledc_update_duty will the duty update.
* @note ledc_set_duty, ledc_set_duty_with_hpoint and ledc_update_duty are not thread-safe, do not call these functions to
* control one LEDC channel in different tasks at the same time.
* A thread-safe version of API is ledc_set_duty_and_update.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
/**
* @brief LEDC get duty
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
*
* @return
* - LEDC_ERR_DUTY if parameter error
* - Others Current LEDC duty
*/
uint32_t ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
/**
* @brief LEDC set gradient
* Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param duty Set the start of the gradient duty, the range of duty setting is [0, (2**duty_resolution)]
* @param fade_direction Set the direction of the gradient
* @param step_num Set the number of the gradient
* @param duty_cycle_num Set how many LEDC tick each time the gradient lasts
* @param duty_scale Set gradient change amplitude
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
uint32_t step_num, uint32_t duty_cycle_num, uint32_t duty_scale);
/**
* @brief Register LEDC interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* @param fn Interrupt handler function.
* @param arg User-supplied argument passed to the handler function.
* @param 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.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error.
*/
esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, ledc_isr_handle_t *handle);
/**
* @brief Configure LEDC settings
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_sel Timer index (0-3), there are 4 timers in LEDC module
* @param clock_divider Timer clock divide value, the timer clock is divided from the selected clock source
* @param duty_resolution Resolution of duty setting in number of bits. The range of duty values is [0, (2**duty_resolution)]
* @param clk_src Select LEDC source clock.
*
* @return
* - (-1) Parameter error
* - Other Current LEDC duty
*/
esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t clock_divider, uint32_t duty_resolution, ledc_clk_src_t clk_src);
/**
* @brief Reset LEDC timer
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
/**
* @brief Pause LEDC timer counter
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*
*/
esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
/**
* @brief Resume LEDC timer
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, ledc_timer_t timer_sel);
/**
* @brief Bind LEDC channel with the selected timer
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel index (0-7), select from ledc_channel_t
* @param timer_sel LEDC timer index (0-3), select from ledc_timer_t
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_timer_t timer_sel);
/**
* @brief Set LEDC fade function.
* @note Call ledc_fade_func_install() once before calling this function.
* Call ledc_fade_start() after this to start fading.
* @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to
* control one LEDC channel in different tasks at the same time.
* A thread-safe version of API is ledc_set_fade_step_and_start
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
* @param channel LEDC channel index (0-7), select from ledc_channel_t
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
* @param scale Controls the increase or decrease step scale.
* @param cycle_num increase or decrease the duty every cycle_num cycles
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num);
/**
* @brief Set LEDC fade function, with a limited time.
* @note Call ledc_fade_func_install() once before calling this function.
* Call ledc_fade_start() after this to start fading.
* @note ledc_set_fade_with_step, ledc_set_fade_with_time and ledc_fade_start are not thread-safe, do not call these functions to
* control one LEDC channel in different tasks at the same time.
* A thread-safe version of API is ledc_set_fade_step_and_start
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode. ,
* @param channel LEDC channel index (0-7), select from ledc_channel_t
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
* @param max_fade_time_ms The maximum time of the fading ( ms ).
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, int max_fade_time_ms);
/**
* @brief Install LEDC fade function. This function will occupy interrupt of LEDC module.
* @param 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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function already installed.
*/
esp_err_t ledc_fade_func_install(int intr_alloc_flags);
/**
* @brief Uninstall LEDC fade function.
*
*/
void ledc_fade_func_uninstall(void);
/**
* @brief Start LEDC fading.
* @note Call ledc_fade_func_install() once before calling this function.
* Call this API right after ledc_set_fade_with_time or ledc_set_fade_with_step before to start fading.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel number
* @param fade_mode Whether to block until fading done.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_ERR_INVALID_ARG Parameter error.
*/
esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t fade_mode);
/**
* @brief A thread-safe API to set duty for LEDC channel and return when duty updated.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
*
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel (0-7), select from ledc_channel_t
* @param duty Set the LEDC duty, the range of duty setting is [0, (2**duty_resolution)]
* @param hpoint Set the LEDC hpoint value(max: 0xfffff)
*
*/
esp_err_t ledc_set_duty_and_update(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty, uint32_t hpoint);
/**
* @brief A thread-safe API to set and start LEDC fade function, with a limited time.
* @note Call ledc_fade_func_install() once, before calling this function.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel index (0-7), select from ledc_channel_t
* @param target_duty Target duty of fading.( 0 - (2 ** duty_resolution - 1)))
* @param max_fade_time_ms The maximum time of the fading ( ms ).
* @param fade_mode choose blocking or non-blocking mode
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_time_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t max_fade_time_ms, ledc_fade_mode_t fade_mode);
/**
* @brief A thread-safe API to set and start LEDC fade function.
* @note Call ledc_fade_func_install() once before calling this function.
* @note If a fade operation is running in progress on that channel, the driver would not allow it to be stopped.
* Other duty operations will have to wait until the fade operation has finished.
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
* @param channel LEDC channel index (0-7), select from ledc_channel_t
* @param target_duty Target duty of fading [0, (2**duty_resolution) - 1]
* @param scale Controls the increase or decrease step scale.
* @param cycle_num increase or decrease the duty every cycle_num cycles
* @param fade_mode choose blocking or non-blocking mode
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE Fade function not installed.
* - ESP_FAIL Fade function init error
*/
esp_err_t ledc_set_fade_step_and_start(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t target_duty, uint32_t scale, uint32_t cycle_num, ledc_fade_mode_t fade_mode);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,664 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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"
#if SOC_MCPWM_SUPPORTED
#include "esp_err.h"
#include "soc/soc.h"
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#include "hal/mcpwm_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IO signals for the MCPWM
*
* - 6 MCPWM output pins that generate PWM signals
* - 3 MCPWM fault input pins to detect faults like overcurrent, overvoltage, etc.
* - 3 MCPWM sync input pins to synchronize MCPWM outputs signals
* - 3 MCPWM capture input pins to gather feedback from controlled motors, using e.g. hall sensors
*/
typedef enum {
MCPWM0A = 0, /*!<PWM0A output pin*/
MCPWM0B, /*!<PWM0B output pin*/
MCPWM1A, /*!<PWM1A output pin*/
MCPWM1B, /*!<PWM1B output pin*/
MCPWM2A, /*!<PWM2A output pin*/
MCPWM2B, /*!<PWM2B output pin*/
MCPWM_SYNC_0, /*!<SYNC0 input pin*/
MCPWM_SYNC_1, /*!<SYNC1 input pin*/
MCPWM_SYNC_2, /*!<SYNC2 input pin*/
MCPWM_FAULT_0, /*!<FAULT0 input pin*/
MCPWM_FAULT_1, /*!<FAULT1 input pin*/
MCPWM_FAULT_2, /*!<FAULT2 input pin*/
MCPWM_CAP_0 = 84, /*!<CAP0 input pin*/
MCPWM_CAP_1, /*!<CAP1 input pin*/
MCPWM_CAP_2, /*!<CAP2 input pin*/
} mcpwm_io_signals_t;
/**
* @brief MCPWM pin number for
*
*/
typedef struct {
int mcpwm0a_out_num; /*!<MCPWM0A out pin*/
int mcpwm0b_out_num; /*!<MCPWM0A out pin*/
int mcpwm1a_out_num; /*!<MCPWM0A out pin*/
int mcpwm1b_out_num; /*!<MCPWM0A out pin*/
int mcpwm2a_out_num; /*!<MCPWM0A out pin*/
int mcpwm2b_out_num; /*!<MCPWM0A out pin*/
int mcpwm_sync0_in_num; /*!<SYNC0 in pin*/
int mcpwm_sync1_in_num; /*!<SYNC1 in pin*/
int mcpwm_sync2_in_num; /*!<SYNC2 in pin*/
int mcpwm_fault0_in_num; /*!<FAULT0 in pin*/
int mcpwm_fault1_in_num; /*!<FAULT1 in pin*/
int mcpwm_fault2_in_num; /*!<FAULT2 in pin*/
int mcpwm_cap0_in_num; /*!<CAP0 in pin*/
int mcpwm_cap1_in_num; /*!<CAP1 in pin*/
int mcpwm_cap2_in_num; /*!<CAP2 in pin*/
} mcpwm_pin_config_t;
/**
* @brief Select MCPWM unit
*/
typedef enum {
MCPWM_UNIT_0 = 0, /*!<MCPWM unit0 selected*/
MCPWM_UNIT_1, /*!<MCPWM unit1 selected*/
MCPWM_UNIT_MAX, /*!<Num of MCPWM units on ESP32*/
} mcpwm_unit_t;
_Static_assert(MCPWM_UNIT_MAX == SOC_MCPWM_GROUPS, "MCPWM unit number not equal to chip capabilities");
/**
* @brief Select MCPWM timer
*/
typedef enum {
MCPWM_TIMER_0 = 0, /*!<Select MCPWM timer0*/
MCPWM_TIMER_1, /*!<Select MCPWM timer1*/
MCPWM_TIMER_2, /*!<Select MCPWM timer2*/
MCPWM_TIMER_MAX, /*!<Num of MCPWM timers on ESP32*/
} mcpwm_timer_t;
/**
* @brief Select MCPWM operator
*/
typedef enum {
MCPWM_GEN_A = 0, /*!<Select MCPWMXA, where 'X' is operator number*/
MCPWM_GEN_B, /*!<Select MCPWMXB, where 'X' is operator number*/
MCPWM_GEN_MAX, /*!<Num of generators to each operator of MCPWM*/
} mcpwm_generator_t;
//definitions and macros to be back-compatible before IDFv4.1
#define MCPWM_OPR_A MCPWM_GEN_A ///< @deprecated
#define MCPWM_OPR_B MCPWM_GEN_B ///< @deprecated
#define MCPWM_OPR_MAX MCPWM_GEN_MAX ///< @deprecated
typedef mcpwm_generator_t mcpwm_operator_t; ///< @deprecated
/**
* @brief MCPWM carrier oneshot mode, in this mode the width of the first pulse of carrier can be programmed
*/
typedef enum {
MCPWM_ONESHOT_MODE_DIS = 0, /*!<Enable oneshot mode*/
MCPWM_ONESHOT_MODE_EN, /*!<Disable oneshot mode*/
} mcpwm_carrier_os_t;
/**
* @brief MCPWM carrier output inversion, high frequency carrier signal active with MCPWM signal is high
*/
typedef enum {
MCPWM_CARRIER_OUT_IVT_DIS = 0, /*!<Enable carrier output inversion*/
MCPWM_CARRIER_OUT_IVT_EN, /*!<Disable carrier output inversion*/
} mcpwm_carrier_out_ivt_t;
/**
* @brief MCPWM select fault signal input
*/
typedef enum {
MCPWM_SELECT_F0 = 0, /*!<Select F0 as input*/
MCPWM_SELECT_F1, /*!<Select F1 as input*/
MCPWM_SELECT_F2, /*!<Select F2 as input*/
} mcpwm_fault_signal_t;
/**
* @brief MCPWM select triggering level of fault signal
*/
typedef enum {
MCPWM_LOW_LEVEL_TGR = 0, /*!<Fault condition occurs when fault input signal goes from high to low, currently not supported*/
MCPWM_HIGH_LEVEL_TGR, /*!<Fault condition occurs when fault input signal goes low to high*/
} mcpwm_fault_input_level_t;
/// @deprecated MCPWM select action to be taken on MCPWMXA when fault occurs
typedef mcpwm_output_action_t mcpwm_action_on_pwmxa_t;
#define MCPWM_NO_CHANGE_IN_MCPWMXA MCPWM_ACTION_NO_CHANGE /*!< @deprecated No change in MCPWMXA output*/
#define MCPWM_FORCE_MCPWMXA_LOW MCPWM_ACTION_FORCE_LOW /*!< @deprecated Make MCPWMXA output low*/
#define MCPWM_FORCE_MCPWMXA_HIGH MCPWM_ACTION_FORCE_HIGH /*!< @deprecated Make MCPWMXA output high*/
#define MCPWM_TOG_MCPWMXA MCPWM_ACTION_TOGGLE /*!< @deprecated Make MCPWMXA output toggle*/
/// @deprecated MCPWM select action to be taken on MCPWMXB when fault occurs
typedef mcpwm_output_action_t mcpwm_action_on_pwmxb_t;
#define MCPWM_NO_CHANGE_IN_MCPWMXB MCPWM_ACTION_NO_CHANGE /*!< @deprecated No change in MCPWMXB output*/
#define MCPWM_FORCE_MCPWMXB_LOW MCPWM_ACTION_FORCE_LOW /*!< @deprecated Make MCPWMXB output low*/
#define MCPWM_FORCE_MCPWMXB_HIGH MCPWM_ACTION_FORCE_HIGH /*!< @deprecated Make MCPWMXB output high*/
#define MCPWM_TOG_MCPWMXB MCPWM_ACTION_TOGGLE /*!< @deprecated Make MCPWMXB output toggle*/
/**
* @brief MCPWM select capture signal input
*/
typedef enum {
MCPWM_SELECT_CAP0 = 0, /*!<Select CAP0 as input*/
MCPWM_SELECT_CAP1, /*!<Select CAP1 as input*/
MCPWM_SELECT_CAP2, /*!<Select CAP2 as input*/
} mcpwm_capture_signal_t;
/**
* @brief MCPWM config structure
*/
typedef struct {
uint32_t frequency; /*!<Set frequency of MCPWM in Hz*/
float cmpr_a; /*!<Set % duty cycle for operator a(MCPWMXA), i.e for 62.3% duty cycle, duty_a = 62.3*/
float cmpr_b; /*!<Set % duty cycle for operator b(MCPWMXB), i.e for 48% duty cycle, duty_b = 48.0*/
mcpwm_duty_type_t duty_mode; /*!<Set type of duty cycle*/
mcpwm_counter_type_t counter_mode; /*!<Set type of MCPWM counter*/
} mcpwm_config_t;
/**
* @brief MCPWM config carrier structure
*/
typedef struct {
uint8_t carrier_period; /*!<Set carrier period = (carrier_period + 1)*800ns, carrier_period should be < 16*/
uint8_t carrier_duty; /*!<Set carrier duty cycle, carrier_duty should be less than 8 (increment every 12.5%)*/
uint8_t pulse_width_in_os; /*!<Set pulse width of first pulse in one shot mode = (carrier period)*(pulse_width_in_os + 1), should be less then 16*/
mcpwm_carrier_os_t carrier_os_mode; /*!<Enable or disable carrier oneshot mode*/
mcpwm_carrier_out_ivt_t carrier_ivt_mode; /*!<Invert output of carrier*/
} mcpwm_carrier_config_t;
/**
* @brief This function initializes each gpio signal for MCPWM
* @note
* This function initializes one gpio at a time.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param io_signal set MCPWM signals, each MCPWM unit has 6 output(MCPWMXA, MCPWMXB) and 9 input(SYNC_X, FAULT_X, CAP_X)
* 'X' is timer_num(0-2)
* @param gpio_num set this to configure gpio for MCPWM, if you want to use gpio16, gpio_num = 16
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t io_signal, int gpio_num);
/**
* @brief Initialize MCPWM gpio structure
* @note
* This function can be used to initialize more then one gpio at a time.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param mcpwm_pin MCPWM pin structure
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_pin(mcpwm_unit_t mcpwm_num, const mcpwm_pin_config_t *mcpwm_pin);
/**
* @brief Initialize MCPWM parameters
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers.
* @param mcpwm_conf configure structure mcpwm_config_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_init( mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_config_t *mcpwm_conf);
/**
* @brief Set frequency(in Hz) of MCPWM timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param frequency set the frequency in Hz of each timer
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint32_t frequency);
/**
* @brief Set duty cycle of each operator(MCPWMXA/MCPWMXB)
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the generator(MCPWMXA/MCPWMXB), 'X' is operator number selected
* @param duty set duty cycle in %(i.e for 62.3% duty cycle, duty = 62.3) of each operator
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, float duty);
/**
* @brief Set duty cycle of each operator(MCPWMXA/MCPWMXB) in us
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
* @param duty_in_us set duty value in microseconds of each operator
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty_in_us(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, uint32_t duty_in_us);
/**
* @brief Set duty either active high or active low(out of phase/inverted)
* @note
* Call this function every time after mcpwm_set_signal_high or mcpwm_set_signal_low to resume with previously set duty cycle
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
* @param duty_type set active low or active high duty type
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_duty_type(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen, mcpwm_duty_type_t duty_type);
/**
* @brief Get frequency of timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - frequency of timer
*/
uint32_t mcpwm_get_frequency(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Get duty cycle of each operator
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the generator(MCPWMXA/MCPWMXB), 'x' is operator number selected
*
* @return
* - duty cycle in % of each operator(56.7 means duty is 56.7%)
*/
float mcpwm_get_duty(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_operator_t gen);
/**
* @brief Use this function to set MCPWM signal high
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_signal_high(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen);
/**
* @brief Use this function to set MCPWM signal low
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param gen set the operator(MCPWMXA/MCPWMXB), 'x' is timer number selected
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_set_signal_low(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_generator_t gen);
/**
* @brief Start MCPWM signal on timer 'x'
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_start(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Start MCPWM signal on timer 'x'
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_stop(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Initialize carrier configuration
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param carrier_conf configure structure mcpwm_carrier_config_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_init(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, const mcpwm_carrier_config_t *carrier_conf);
/**
* @brief Enable MCPWM carrier submodule, for respective timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Disable MCPWM carrier submodule, for respective timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Set period of carrier
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param carrier_period set the carrier period of each timer, carrier period = (carrier_period + 1)*800ns
* (carrier_period <= 15)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_set_period(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint8_t carrier_period);
/**
* @brief Set duty_cycle of carrier
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param carrier_duty set duty_cycle of carrier , carrier duty cycle = carrier_duty*12.5%
* (chop_duty <= 7)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_set_duty_cycle(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint8_t carrier_duty);
/**
* @brief Enable and set width of first pulse in carrier oneshot mode
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param pulse_width set pulse width of first pulse in oneshot mode, width = (carrier period)*(pulse_width +1)
* (pulse_width <= 15)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_oneshot_mode_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, uint8_t pulse_width);
/**
* @brief Disable oneshot mode, width of first pulse = carrier period
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_oneshot_mode_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Enable or disable carrier output inversion
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param carrier_ivt_mode enable or disable carrier output inversion
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_carrier_output_invert(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num,
mcpwm_carrier_out_ivt_t carrier_ivt_mode);
/**
* @brief Enable and initialize deadtime for each MCPWM timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param dt_mode set deadtime mode
* @param red set rising edge delay = red*100ns
* @param fed set rising edge delay = fed*100ns
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_deadtime_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_deadtime_type_t dt_mode,
uint32_t red, uint32_t fed);
/**
* @brief Disable deadtime on MCPWM timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_deadtime_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Initialize fault submodule, currently low level triggering is not supported
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param intput_level set fault signal level, which will cause fault to occur
* @param fault_sig set the fault pin, which needs to be enabled
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_init(mcpwm_unit_t mcpwm_num, mcpwm_fault_input_level_t intput_level, mcpwm_fault_signal_t fault_sig);
/**
* @brief Set oneshot mode on fault detection, once fault occur in oneshot mode reset is required to resume MCPWM signals
* @note
* currently low level triggering is not supported
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param fault_sig set the fault pin, which needs to be enabled for oneshot mode
* @param action_on_pwmxa action to be taken on MCPWMXA when fault occurs, either no change or high or low or toggle
* @param action_on_pwmxb action to be taken on MCPWMXB when fault occurs, either no change or high or low or toggle
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_set_oneshot_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_fault_signal_t fault_sig,
mcpwm_output_action_t action_on_pwmxa, mcpwm_output_action_t action_on_pwmxb);
/**
* @brief Set cycle-by-cycle mode on fault detection, once fault occur in cyc mode MCPWM signal resumes as soon as fault signal becomes inactive
* @note
* currently low level triggering is not supported
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param fault_sig set the fault pin, which needs to be enabled for cyc mode
* @param action_on_pwmxa action to be taken on MCPWMXA when fault occurs, either no change or high or low or toggle
* @param action_on_pwmxb action to be taken on MCPWMXB when fault occurs, either no change or high or low or toggle
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_set_cyc_mode(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_fault_signal_t fault_sig,
mcpwm_output_action_t action_on_pwmxa, mcpwm_output_action_t action_on_pwmxb);
/**
* @brief Disable fault signal
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param fault_sig fault pin, which needs to be disabled
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_fault_deinit(mcpwm_unit_t mcpwm_num, mcpwm_fault_signal_t fault_sig);
/**
* @brief Initialize capture submodule
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param cap_edge set capture edge, BIT(0) - negative edge, BIT(1) - positive edge
* @param cap_sig capture pin, which needs to be enabled
* @param num_of_pulse count time between rising/falling edge between 2 *(pulses mentioned), counter uses APB_CLK
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_capture_enable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig, mcpwm_capture_on_edge_t cap_edge,
uint32_t num_of_pulse);
/**
* @brief Disable capture signal
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param cap_sig capture pin, which needs to be disabled
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_capture_disable(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig);
/**
* @brief Get capture value
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param cap_sig capture pin on which value is to be measured
*
* @return
* Captured value
*/
uint32_t mcpwm_capture_signal_get_value(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig);
/**
* @brief Get edge of capture signal
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param cap_sig capture pin of whose edge is to be determined
*
* @return
* Capture signal edge: 1 - positive edge, 2 - negtive edge
*/
uint32_t mcpwm_capture_signal_get_edge(mcpwm_unit_t mcpwm_num, mcpwm_capture_signal_t cap_sig);
/**
* @brief Initialize sync submodule
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
* @param sync_sig set the synchronization pin, which needs to be enabled
* @param phase_val phase value in 1/1000 (for 86.7%, phase_val = 867) which timer moves to on sync signal
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_sync_enable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, mcpwm_sync_signal_t sync_sig,
uint32_t phase_val);
/**
* @brief Disable sync submodule on given timer
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param timer_num set timer number(0-2) of MCPWM, each MCPWM unit has 3 timers
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t mcpwm_sync_disable(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num);
/**
* @brief Register MCPWM interrupt handler, the handler is an ISR.
* the handler will be attached to the same CPU core that this function is running on.
*
* @param mcpwm_num set MCPWM unit(0-1)
* @param fn interrupt handler function.
* @param arg user-supplied argument passed to the handler function.
* @param 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.
* @param handle pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error.
*/
esp_err_t mcpwm_isr_register(mcpwm_unit_t mcpwm_num, void (*fn)(void *), void *arg, int intr_alloc_flags, intr_handle_t *handle);
#ifdef __cplusplus
}
#endif
#endif //SOC_MCPWM_SUPPORTED

View File

@ -0,0 +1,412 @@
// 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_types.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
#include "driver/gpio.h"
#include "hal/pcnt_types.h"
#include "soc/pcnt_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef intr_handle_t pcnt_isr_handle_t;
/**
* @brief Configure Pulse Counter unit
* @note
* This function will disable three events: PCNT_EVT_L_LIM, PCNT_EVT_H_LIM, PCNT_EVT_ZERO.
*
* @param pcnt_config Pointer of Pulse Counter unit configure parameter
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver already initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_unit_config(const pcnt_config_t *pcnt_config);
/**
* @brief Get pulse counter value
*
* @param pcnt_unit Pulse Counter unit number
* @param count Pointer to accept counter value
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t *count);
/**
* @brief Pause PCNT counter of PCNT unit
*
* @param pcnt_unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit);
/**
* @brief Resume counting for PCNT counter
*
* @param pcnt_unit PCNT unit number, select from pcnt_unit_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit);
/**
* @brief Clear and reset PCNT counter value to zero
*
* @param pcnt_unit PCNT unit number, select from pcnt_unit_t
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_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 pcnt_unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
/**
* @brief Disable PCNT interrupt for PCNT unit
*
* @param pcnt_unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit);
/**
* @brief Enable PCNT event of PCNT unit
*
* @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).
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
/**
* @brief Disable PCNT event of PCNT unit
*
* @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).
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type);
/**
* @brief Set PCNT event value of PCNT unit
*
* @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
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value);
/**
* @brief Get PCNT event value of PCNT unit
*
* @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
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value);
/**
* @brief Get PCNT event status of PCNT unit
*
* @param unit PCNT unit number
* @param status Pointer to accept event status word
* @return
*
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_get_event_status(pcnt_unit_t unit, uint32_t *status);
/**
* @brief Unregister PCNT interrupt handler (registered by pcnt_isr_register), the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* If the interrupt service is registered by pcnt_isr_service_install, please call pcnt_isr_service_uninstall instead
*
* @param handle handle to unregister the ISR service.
*
* @return
* - ESP_OK Success
* - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
* - ESP_ERR_INVALID_ARG Function pointer error.
*/
esp_err_t pcnt_isr_unregister(pcnt_isr_handle_t handle);
/**
* @brief Register PCNT interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
* Please do not use pcnt_isr_service_install if this function was called.
*
* @param fn Interrupt handler function.
* @param arg Parameter for handler function
* @param 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.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here. Calling pcnt_isr_unregister to unregister this ISR service if needed,
* but only if the handle is not NULL.
*
* @return
* - ESP_OK Success
* - ESP_ERR_NOT_FOUND Can not find the interrupt that matches the flags.
* - ESP_ERR_INVALID_ARG Function pointer error.
*/
esp_err_t pcnt_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, pcnt_isr_handle_t *handle);
/**
* @brief Configure PCNT pulse signal input pin and control input pin
*
* @param unit PCNT unit number
* @param channel PCNT channel number
* @param pulse_io Pulse signal input GPIO
* @param ctrl_io Control signal input GPIO
*
* @note Set the signal input to PCNT_PIN_NOT_USED if unused.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io);
/**
* @brief Enable PCNT input filter
*
* @param unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_filter_enable(pcnt_unit_t unit);
/**
* @brief Disable PCNT input filter
*
* @param unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_filter_disable(pcnt_unit_t unit);
/**
* @brief Set PCNT filter value
*
* @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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val);
/**
* @brief Get PCNT filter value
*
* @param unit PCNT unit number
* @param filter_val Pointer to accept PCNT filter value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val);
/**
* @brief Set PCNT counter mode
*
* @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
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_set_mode(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);
/**
* @brief Add ISR handler for specified unit.
*
* Call this function after using pcnt_isr_service_install() to
* install the PCNT driver's ISR handler service.
*
* The ISR handlers do not need to be declared with IRAM_ATTR,
* unless you pass the ESP_INTR_FLAG_IRAM flag when allocating the
* ISR in pcnt_isr_service_install().
*
* This ISR handler will be called from an ISR. So there is a stack
* size limit (configurable as "ISR stack size" in menuconfig). This
* limit is smaller compared to a global PCNT interrupt handler due
* to the additional level of indirection.
*
* @param unit PCNT unit number
* @param isr_handler Interrupt handler function.
* @param args Parameter for handler function
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_isr_handler_add(pcnt_unit_t unit, void(*isr_handler)(void *), void *args);
/**
* @brief Install PCNT ISR service.
* @note We can manage different interrupt service for each unit.
* This function will use the default ISR handle service, Calling pcnt_isr_service_uninstall to
* uninstall the default service if needed. Please do not use pcnt_isr_register if this function was called.
*
* @param 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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_NO_MEM No memory to install this service
* - ESP_ERR_INVALID_STATE ISR service already installed
*/
esp_err_t pcnt_isr_service_install(int intr_alloc_flags);
/**
* @brief Uninstall PCNT ISR service, freeing related resources.
*/
void pcnt_isr_service_uninstall(void);
/**
* @brief Delete ISR handler for specified unit.
*
* @param unit PCNT unit number
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE pcnt driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t pcnt_isr_handler_remove(pcnt_unit_t unit);
/**
* @addtogroup pcnt-examples
*
* @{
*
* EXAMPLE OF PCNT CONFIGURATION
* ==============================
* @code{c}
* //1. Config PCNT unit
* pcnt_config_t pcnt_config = {
* .pulse_gpio_num = 4, //set gpio4 as pulse input gpio
* .ctrl_gpio_num = 5, //set gpio5 as control gpio
* .channel = PCNT_CHANNEL_0, //use unit 0 channel 0
* .lctrl_mode = PCNT_MODE_REVERSE, //when control signal is low, reverse the primary counter mode(inc->dec/dec->inc)
* .hctrl_mode = PCNT_MODE_KEEP, //when control signal is high, keep the primary counter mode
* .pos_mode = PCNT_COUNT_INC, //increment the counter
* .neg_mode = PCNT_COUNT_DIS, //keep the counter value
* .counter_h_lim = 10,
* .counter_l_lim = -10,
* };
* pcnt_unit_config(&pcnt_config); //init unit
* @endcode
*
* EXAMPLE OF PCNT EVENT SETTING
* ==============================
* @code{c}
* //2. Configure PCNT watchpoint event.
* pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 5); //set thres1 value
* pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1); //enable thres1 event
* @endcode
*
* For more examples please refer to PCNT example code in IDF_PATH/examples
*
* @}
*/
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,117 @@
// Copyright 2015-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.
#ifndef _DRIVER_PERIPH_CTRL_H_
#define _DRIVER_PERIPH_CTRL_H_
#include "soc/periph_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief enable peripheral module
*
* @param[in] periph : Peripheral module name
*
* Clock for the module will be ungated, and reset de-asserted.
*
* @note If periph_module_enable is called a number of times,
* periph_module_disable has to be called the same number of times
* in order to put the peripheral into disabled state.
*
* @return NULL
*
*/
void periph_module_enable(periph_module_t periph);
/**
* @brief disable peripheral module
*
* @param[in] periph : Peripheral module name
*
* Clock for the module will be gated, reset asserted.
*
* @note If periph_module_enable is called a number of times,
* periph_module_disable has to be called the same number of times
* in order to put the peripheral into disabled state.
*
* @return NULL
*
*/
void periph_module_disable(periph_module_t periph);
/**
* @brief reset peripheral module
*
* @param[in] periph : Peripheral module name
*
* Reset will asserted then de-assrted for the peripheral.
*
* Calling this function does not enable or disable the clock for the module.
*
* @return NULL
*
*/
void periph_module_reset(periph_module_t periph);
/**
* @brief enable wifi bt common module
*
* @note If wifi_bt_common_module_enable is called a number of times,
* wifi_bt_common_module_disable has to be called the same number of times
* in order to put the peripheral into disabled state.
*
* @return NULL
*
*/
void wifi_bt_common_module_enable(void);
/**
* @brief disable wifi bt common module
*
* @note If wifi_bt_common_module_enable is called a number of times,
* wifi_bt_common_module_disable has to be called the same number of times
* in order to put the peripheral into disabled state.
*
* @return NULL
*
*/
void wifi_bt_common_module_disable(void);
/**
* @brief enable wifi module
*
* @note Enable wifi module only.
*
* @return NULL
*
*/
void wifi_module_enable(void);
/**
* @brief disable wifi module
*
* @note Disable wifi module only.
*
* @return NULL
*
*/
void wifi_module_disable(void);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_PERIPH_CTRL_H_ */

View File

@ -0,0 +1,924 @@
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/ringbuf.h"
#include "soc/rmt_struct.h"
#include "hal/rmt_types.h"
#define RMT_CHANNEL_FLAGS_AWARE_DFS (1 << 0) /*!< Channel can work during APB clock scaling */
#define RMT_CHANNEL_FLAGS_INVERT_SIG (1 << 1) /*!< Invert RMT signal */
/** @cond */
#define RMT_CHANNEL_FLAGS_ALWAYS_ON RMT_CHANNEL_FLAGS_AWARE_DFS /*!< Deprecated name, defined here for compatibility */
/** @endcond */
/**
* @brief Define memory space of each RMT channel (in words = 4 bytes)
*
*/
#define RMT_MEM_ITEM_NUM SOC_RMT_MEM_WORDS_PER_CHANNEL
/**
* @brief Data struct of RMT TX configure parameters
*/
typedef struct {
uint32_t carrier_freq_hz; /*!< RMT carrier frequency */
rmt_carrier_level_t carrier_level; /*!< Level of the RMT output, when the carrier is applied */
rmt_idle_level_t idle_level; /*!< RMT idle level */
uint8_t carrier_duty_percent; /*!< RMT carrier duty (%) */
#if SOC_RMT_SUPPORT_TX_LOOP_COUNT
uint32_t loop_count; /*!< Maximum loop count */
#endif
bool carrier_en; /*!< RMT carrier enable */
bool loop_en; /*!< Enable sending RMT items in a loop */
bool idle_output_en; /*!< RMT idle level output enable */
} rmt_tx_config_t;
/**
* @brief Data struct of RMT RX configure parameters
*/
typedef struct {
uint16_t idle_threshold; /*!< RMT RX idle threshold */
uint8_t filter_ticks_thresh; /*!< RMT filter tick number */
bool filter_en; /*!< RMT receiver filter enable */
#if SOC_RMT_SUPPORT_RX_DEMODULATION
bool rm_carrier; /*!< RMT receiver remove carrier enable */
uint32_t carrier_freq_hz; /*!< RMT carrier frequency */
uint8_t carrier_duty_percent; /*!< RMT carrier duty (%) */
rmt_carrier_level_t carrier_level; /*!< The level to remove the carrier */
#endif
} rmt_rx_config_t;
/**
* @brief Data struct of RMT configure parameters
*/
typedef struct {
rmt_mode_t rmt_mode; /*!< RMT mode: transmitter or receiver */
rmt_channel_t channel; /*!< RMT channel */
gpio_num_t gpio_num; /*!< RMT GPIO number */
uint8_t clk_div; /*!< RMT channel counter divider */
uint8_t mem_block_num; /*!< RMT memory block number */
uint32_t flags; /*!< RMT channel extra configurations, OR'd with RMT_CHANNEL_FLAGS_[*] */
union {
rmt_tx_config_t tx_config; /*!< RMT TX parameter */
rmt_rx_config_t rx_config; /*!< RMT RX parameter */
};
} rmt_config_t;
/**
* @brief Default configuration for Tx channel
*
*/
#define RMT_DEFAULT_CONFIG_TX(gpio, channel_id) \
{ \
.rmt_mode = RMT_MODE_TX, \
.channel = channel_id, \
.gpio_num = gpio, \
.clk_div = 80, \
.mem_block_num = 1, \
.flags = 0, \
.tx_config = { \
.carrier_freq_hz = 38000, \
.carrier_level = RMT_CARRIER_LEVEL_HIGH, \
.idle_level = RMT_IDLE_LEVEL_LOW, \
.carrier_duty_percent = 33, \
.carrier_en = false, \
.loop_en = false, \
.idle_output_en = true, \
} \
}
/**
* @brief Default configuration for RX channel
*
*/
#define RMT_DEFAULT_CONFIG_RX(gpio, channel_id) \
{ \
.rmt_mode = RMT_MODE_RX, \
.channel = channel_id, \
.gpio_num = gpio, \
.clk_div = 80, \
.mem_block_num = 1, \
.flags = 0, \
.rx_config = { \
.idle_threshold = 12000, \
.filter_ticks_thresh = 100, \
.filter_en = true, \
} \
}
/**
* @brief RMT interrupt handle
*
*/
typedef intr_handle_t rmt_isr_handle_t;
/**
* @brief Type of RMT Tx End callback function
*
*/
typedef void (*rmt_tx_end_fn_t)(rmt_channel_t channel, void *arg);
/**
* @brief Structure encapsulating a RMT TX end callback
*/
typedef struct {
rmt_tx_end_fn_t function; /*!< Function which is called on RMT TX end */
void *arg; /*!< Optional argument passed to function */
} rmt_tx_end_callback_t;
/**
* @brief User callback function to convert uint8_t type data to rmt format(rmt_item32_t).
*
* This function may be called from an ISR, so, the code should be short and efficient.
*
* @param src Pointer to the buffer storing the raw data that needs to be converted to rmt format.
* @param[out] dest Pointer to the buffer storing the rmt format data.
* @param src_size The raw data size.
* @param wanted_num The number of rmt format data that wanted to get.
* @param[out] translated_size The size of the raw data that has been converted to rmt format,
* it should return 0 if no data is converted in user callback.
* @param[out] item_num The number of the rmt format data that actually converted to,
* it can be less than wanted_num if there is not enough raw data, but cannot exceed wanted_num.
* it should return 0 if no data was converted.
*
* @note
* In fact, item_num should be a multiple of translated_size, e.g. :
* When we convert each byte of uint8_t type data to rmt format data,
* the relation between item_num and translated_size should be `item_num = translated_size*8`.
*/
typedef void (*sample_to_rmt_t)(const void *src, rmt_item32_t *dest, size_t src_size, size_t wanted_num, size_t *translated_size, size_t *item_num);
/**
* @brief Set RMT clock divider, channel clock is divided from source clock.
*
* @param channel RMT channel
* @param div_cnt RMT counter clock divider
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt);
/**
* @brief Get RMT clock divider, channel clock is divided from source clock.
*
* @param channel RMT channel
* @param div_cnt pointer to accept RMT counter divider
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t *div_cnt);
/**
* @brief Set RMT RX idle threshold value
*
* In receive mode, when no edge is detected on the input signal
* for longer than idle_thres channel clock cycles,
* the receive process is finished.
*
* @param channel RMT channel
* @param thresh RMT RX idle threshold
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh);
/**
* @brief Get RMT idle threshold value.
*
* In receive mode, when no edge is detected on the input signal
* for longer than idle_thres channel clock cycles,
* the receive process is finished.
*
* @param channel RMT channel
* @param thresh pointer to accept RMT RX idle threshold value
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh);
/**
* @brief Set RMT memory block number for RMT channel
*
* This function is used to configure the amount of memory blocks allocated to channel n
* The 8 channels share a 512x32-bit RAM block which can be read and written
* by the processor cores over the APB bus, as well as read by the transmitters
* and written by the receivers.
*
* The RAM address range for channel n is start_addr_CHn to end_addr_CHn, which are defined by:
* Memory block start address is RMT_CHANNEL_MEM(n) (in soc/rmt_reg.h),
* that is, start_addr_chn = RMT base address + 0x800 + 64 4 n, and
* end_addr_chn = RMT base address + 0x800 + 64 4 n + 64 4 RMT_MEM_SIZE_CHn mod 512 4
*
* @note
* If memory block number of one channel is set to a value greater than 1, this channel will occupy the memory
* block of the next channel.
* Channel 0 can use at most 8 blocks of memory, accordingly channel 7 can only use one memory block.
*
* @param channel RMT channel
* @param rmt_mem_num RMT RX memory block number, one block has 64 * 32 bits.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num);
/**
* @brief Get RMT memory block number
*
* @param channel RMT channel
* @param rmt_mem_num Pointer to accept RMT RX memory block number
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t *rmt_mem_num);
/**
* @brief Configure RMT carrier for TX signal.
*
* Set different values for carrier_high and carrier_low to set different frequency of carrier.
* The unit of carrier_high/low is the source clock tick, not the divided channel counter clock.
*
* @param channel RMT channel
* @param carrier_en Whether to enable output carrier.
* @param high_level High level duration of carrier
* @param low_level Low level duration of carrier.
* @param carrier_level Configure the way carrier wave is modulated for channel.
* - 1'b1:transmit on low output level
* - 1'b0:transmit on high output level
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t high_level, uint16_t low_level, rmt_carrier_level_t carrier_level);
/**
* @brief Set RMT memory in low power mode.
*
* Reduce power consumed by memory. 1:memory is in low power state.
*
* @param channel RMT channel
* @param pd_en RMT memory low power enable.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en);
/**
* @brief Get RMT memory low power mode.
*
* @param channel RMT channel
* @param pd_en Pointer to accept RMT memory low power mode.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool *pd_en);
/**
* @brief Set RMT start sending data from memory.
*
* @param channel RMT channel
* @param tx_idx_rst Set true to reset memory index for TX.
* Otherwise, transmitter will continue sending from the last index in memory.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst);
/**
* @brief Set RMT stop sending.
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_tx_stop(rmt_channel_t channel);
/**
* @brief Set RMT start receiving data.
*
* @param channel RMT channel
* @param rx_idx_rst Set true to reset memory index for receiver.
* Otherwise, receiver will continue receiving data to the last index in memory.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst);
/**
* @brief Set RMT stop receiving data.
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_rx_stop(rmt_channel_t channel);
/**
* @brief Reset RMT TX memory
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_tx_memory_reset(rmt_channel_t channel);
/**
* @brief Reset RMT RX memory
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_rx_memory_reset(rmt_channel_t channel);
/**
* @brief Set RMT memory owner.
* @note Setting memroy is only valid for RX channel.
*
* @param channel RMT channel
* @param owner To set when the transmitter or receiver can process the memory of channel.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner);
/**
* @brief Get RMT memory owner.
*
* @param channel RMT channel
* @param owner Pointer to get memory owner.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t *owner);
/**
* @brief Set RMT tx loop mode.
*
* @param channel RMT channel
* @param loop_en Enable RMT transmitter loop sending mode.
* If set true, transmitter will continue sending from the first data
* to the last data in channel over and over again in a loop.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en);
/**
* @brief Get RMT tx loop mode.
*
* @param channel RMT channel
* @param loop_en Pointer to accept RMT transmitter loop sending mode.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool *loop_en);
/**
* @brief Set RMT RX filter.
*
* In receive mode, channel will ignore input pulse when the pulse width is smaller than threshold.
* Counted in source clock, not divided counter clock.
*
* @param channel RMT channel
* @param rx_filter_en To enable RMT receiver filter.
* @param thresh Threshold of pulse width for receiver.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh);
/**
* @brief Set RMT source clock
*
* RMT module has two clock sources:
* 1. APB clock which is 80Mhz
* 2. REF tick clock, which would be 1Mhz (not supported in this version).
*
* @param channel RMT channel
* @param base_clk To choose source clock for RMT module.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk);
/**
* @brief Get RMT source clock
*
* RMT module has two clock sources:
* 1. APB clock which is 80Mhz
* 2. REF tick clock, which would be 1Mhz (not supported in this version).
*
* @param channel RMT channel
* @param src_clk Pointer to accept source clock for RMT module.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t *src_clk);
/**
* @brief Set RMT idle output level for transmitter
*
* @param channel RMT channel
* @param idle_out_en To enable idle level output.
* @param level To set the output signal's level for channel in idle state.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level);
/**
* @brief Get RMT idle output level for transmitter
*
* @param channel RMT channel
* @param idle_out_en Pointer to accept value of enable idle.
* @param level Pointer to accept value of output signal's level in idle state for specified channel.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_idle_level(rmt_channel_t channel, bool *idle_out_en, rmt_idle_level_t *level);
/**
* @brief Get RMT status
*
* @param channel RMT channel
* @param status Pointer to accept channel status.
* Please refer to RMT_CHnSTATUS_REG(n=0~7) in `rmt_reg.h` for more details of each field.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t *status);
/**
* @brief Set RMT RX interrupt enable
*
* @param channel RMT channel
* @param en enable or disable RX interrupt.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en);
/**
* @brief Set RMT RX error interrupt enable
*
* @param channel RMT channel
* @param en enable or disable RX err interrupt.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en);
/**
* @brief Set RMT TX interrupt enable
*
* @param channel RMT channel
* @param en enable or disable TX interrupt.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
/**
* @brief Set RMT TX threshold event interrupt enable
*
* An interrupt will be triggered when the number of transmitted items reaches the threshold value
*
* @param channel RMT channel
* @param en enable or disable TX event interrupt.
* @param evt_thresh RMT event interrupt threshold value
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
/**
* @brief Configure the GPIO used by RMT channel
*
* @param channel RMT channel
* @param mode RMT mode, either RMT_MODE_TX or RMT_MODE_RX
* @param gpio_num GPIO number, which is connected with certain RMT signal
* @param invert_signal Invert RMT signal physically by GPIO matrix
*
* @return
* - ESP_ERR_INVALID_ARG Configure RMT GPIO failed because of wrong parameter
* - ESP_OK Configure RMT GPIO successfully
*/
esp_err_t rmt_set_gpio(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num, bool invert_signal);
/**
* @brief Configure RMT parameters
*
* @param rmt_param RMT parameter struct
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_config(const rmt_config_t *rmt_param);
/**
* @brief Register RMT interrupt handler, the handler is an ISR.
*
* The handler will be attached to the same CPU core that this function is running on.
*
* @note If you already called rmt_driver_install to use system RMT driver,
* please do not register ISR handler again.
*
* @param fn Interrupt handler function.
* @param arg Parameter for the handler function
* @param 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.
* @param handle If non-zero, a handle to later clean up the ISR gets stored here.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Function pointer error.
* - ESP_FAIL System driver installed, can not register ISR handler for RMT
*/
esp_err_t rmt_isr_register(void (*fn)(void *), void *arg, int intr_alloc_flags, rmt_isr_handle_t *handle);
/**
* @brief Deregister previously registered RMT interrupt handler
*
* @param handle Handle obtained from rmt_isr_register
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Handle invalid
*/
esp_err_t rmt_isr_deregister(rmt_isr_handle_t handle);
/**
* @brief Fill memory data of channel with given RMT items.
*
* @param channel RMT channel
* @param item Pointer of items.
* @param item_num RMT sending items number.
* @param mem_offset Index offset of memory.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_fill_tx_items(rmt_channel_t channel, const rmt_item32_t *item, uint16_t item_num, uint16_t mem_offset);
/**
* @brief Initialize RMT driver
*
* @param channel RMT channel
* @param rx_buf_size Size of RMT RX ringbuffer. Can be 0 if the RX ringbuffer is not used.
* @param intr_alloc_flags Flags for the RMT driver interrupt handler. Pass 0 for default flags. See esp_intr_alloc.h for details.
* If ESP_INTR_FLAG_IRAM is used, please do not use the memory allocated from psram when calling rmt_write_items.
*
* @return
* - ESP_ERR_INVALID_STATE Driver is already installed, call rmt_driver_uninstall first.
* - ESP_ERR_NO_MEM Memory allocation failure
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr_alloc_flags);
/**
* @brief Uninstall RMT driver.
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_driver_uninstall(rmt_channel_t channel);
/**
* @brief Get the current status of eight channels.
*
* @note Do not call this function if it is possible that `rmt_driver_uninstall` will be called at the same time.
*
* @param[out] channel_status store the current status of each channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter is NULL
* - ESP_OK Success
*/
esp_err_t rmt_get_channel_status(rmt_channel_status_result_t *channel_status);
/**
* @brief Get speed of channel's internal counter clock.
*
* @param channel RMT channel
* @param[out] clock_hz counter clock speed, in hz
*
* @return
* - ESP_ERR_INVALID_ARG Parameter is NULL
* - ESP_OK Success
*/
esp_err_t rmt_get_counter_clock(rmt_channel_t channel, uint32_t *clock_hz);
/**
* @brief RMT send waveform from rmt_item array.
*
* This API allows user to send waveform with any length.
*
* @param channel RMT channel
* @param rmt_item head point of RMT items array.
* If ESP_INTR_FLAG_IRAM is used, please do not use the memory allocated from psram when calling rmt_write_items.
* @param item_num RMT data item number.
* @param wait_tx_done
* - If set 1, it will block the task and wait for sending done.
* - If set 0, it will not wait and return immediately.
*
* @note
* This function will not copy data, instead, it will point to the original items,
* and send the waveform items.
* If wait_tx_done is set to true, this function will block and will not return until
* all items have been sent out.
* If wait_tx_done is set to false, this function will return immediately, and the driver
* interrupt will continue sending the items. We must make sure the item data will not be
* damaged when the driver is still sending items in driver interrupt.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t *rmt_item, int item_num, bool wait_tx_done);
/**
* @brief Wait RMT TX finished.
*
* @param channel RMT channel
* @param wait_time Maximum time in ticks to wait for transmission to be complete. If set 0, return immediately with ESP_ERR_TIMEOUT if TX is busy (polling).
*
* @return
* - ESP_OK RMT Tx done successfully
* - ESP_ERR_TIMEOUT Exceeded the 'wait_time' given
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Driver not installed
*/
esp_err_t rmt_wait_tx_done(rmt_channel_t channel, TickType_t wait_time);
/**
* @brief Get ringbuffer from RMT.
*
* Users can get the RMT RX ringbuffer handle, and process the RX data.
*
* @param channel RMT channel
* @param buf_handle Pointer to buffer handle to accept RX ringbuffer handle.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t *buf_handle);
/**
* @brief Init rmt translator and register user callback.
* The callback will convert the raw data that needs to be sent to rmt format.
* If a channel is initialized more than once, tha user callback will be replaced by the later.
*
* @param channel RMT channel .
* @param fn Point to the data conversion function.
*
* @return
* - ESP_FAIL Init fail.
* - ESP_OK Init success.
*/
esp_err_t rmt_translator_init(rmt_channel_t channel, sample_to_rmt_t fn);
/**
* @brief Set user context for the translator of specific channel
*
* @param channel RMT channel number
* @param context User context
*
* @return
* - ESP_FAIL Set context fail
* - ESP_OK Set context success
*/
esp_err_t rmt_translator_set_context(rmt_channel_t channel, void *context);
/**
* @brief Get the user context set by 'rmt_translator_set_context'
*
* @note This API must be invoked in the RMT translator callback function,
* and the first argument must be the actual parameter 'item_num' you got in that callback function.
*
* @param item_num Address of the memory which contains the number of translated items (It's from driver's internal memroy)
* @param context Returned User context
*
* @return
* - ESP_FAIL Get context fail
* - ESP_OK Get context success
*/
esp_err_t rmt_translator_get_context(const size_t *item_num, void **context);
/**
* @brief Translate uint8_t type of data into rmt format and send it out.
* Requires rmt_translator_init to init the translator first.
*
* @param channel RMT channel .
* @param src Pointer to the raw data.
* @param src_size The size of the raw data.
* @param wait_tx_done Set true to wait all data send done.
*
* @return
* - ESP_FAIL Send fail
* - ESP_OK Send success
*/
esp_err_t rmt_write_sample(rmt_channel_t channel, const uint8_t *src, size_t src_size, bool wait_tx_done);
/**
* @brief Registers a callback that will be called when transmission ends.
*
* Called by rmt_driver_isr_default in interrupt context.
*
* @note Requires rmt_driver_install to install the default ISR handler.
*
* @param function Function to be called from the default interrupt handler or NULL.
* @param arg Argument which will be provided to the callback when it is called.
*
* @return the previous callback settings (members will be set to NULL if there was none)
*/
rmt_tx_end_callback_t rmt_register_tx_end_callback(rmt_tx_end_fn_t function, void *arg);
#if SOC_RMT_SUPPORT_RX_PINGPONG
/**
* @brief Set RMT RX threshold event interrupt enable
*
* An interrupt will be triggered when the number of received items reaches the threshold value
*
* @param channel RMT channel
* @param en enable or disable RX event interrupt.
* @param evt_thresh RMT event interrupt threshold value
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_rx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
#endif
#if SOC_RMT_SUPPORT_TX_SYNCHRO
/**
* @brief Add channel into a synchronous group (channels in the same group can start transaction simultaneously)
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_add_channel_to_group(rmt_channel_t channel);
/**
* @brief Remove channel out of a group
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_remove_channel_from_group(rmt_channel_t channel);
#endif
#if SOC_RMT_SUPPORT_TX_LOOP_COUNT
/**
* @brief Set loop count for RMT TX channel
*
* @param channel RMT channel
* @param count loop count
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_tx_loop_count(rmt_channel_t channel, uint32_t count);
#endif
/**
* @brief Reset RMT TX/RX memory index.
*
* @param channel RMT channel
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)
__attribute__((deprecated("use rmt_tx_memory_reset or rmt_rx_memory_reset instead")));
/**
* @brief Set mask value to RMT interrupt enable register.
*
* @param mask Bit mask to set to the register
*
*/
void rmt_set_intr_enable_mask(uint32_t mask)
__attribute__((deprecated("interrupt should be handled by driver")));
/**
* @brief Clear mask value to RMT interrupt enable register.
*
* @param mask Bit mask to clear the register
*
*/
void rmt_clr_intr_enable_mask(uint32_t mask)
__attribute__((deprecated("interrupt should be handled by driver")));
/**
* @brief Set RMT pin
*
* @param channel RMT channel
* @param mode TX or RX mode for RMT
* @param gpio_num GPIO number to transmit or receive the signal.
*
* @return
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_OK Success
*/
esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num)
__attribute__((deprecated("use rmt_set_gpio instead")));
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,56 @@
// Copyright 2016-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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"
#include "esp_intr_alloc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register a handler for specific RTC_CNTL interrupts
*
* Multiple handlers can be registered using this function. Whenever an
* RTC interrupt happens, all handlers with matching rtc_intr_mask values
* will be called.
*
* @param handler handler function to call
* @param handler_arg argument to be passed to the handler
* @param rtc_intr_mask combination of RTC_CNTL_*_INT_ENA bits indicating the
* sources to call the handler for
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM not enough memory to allocate handler structure
* - other errors returned by esp_intr_alloc
*/
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
uint32_t rtc_intr_mask);
/**
* @brief Deregister the handler previously registered using rtc_isr_register
* @param handler handler function to call (as passed to rtc_isr_register)
* @param handler_arg argument of the handler (as passed to rtc_isr_register)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if a handler matching both handler and
* handler_arg isn't registered
*/
esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,321 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_RTC_GPIO_H_
#define _DRIVER_RTC_GPIO_H_
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "soc/soc_caps.h"
#include "soc/rtc_io_periph.h"
#include "hal/rtc_io_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Determine if the specified GPIO is a valid RTC GPIO.
*
* @param gpio_num GPIO number
* @return true if GPIO is valid for RTC GPIO use. false otherwise.
*/
static inline bool rtc_gpio_is_valid_gpio(gpio_num_t gpio_num)
{
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
return (gpio_num < GPIO_PIN_COUNT && rtc_io_num_map[gpio_num] >= 0);
#else
return false;
#endif
}
#define RTC_GPIO_IS_VALID_GPIO(gpio_num) rtc_gpio_is_valid_gpio(gpio_num) // Deprecated, use rtc_gpio_is_valid_gpio()
/**
* @brief Get RTC IO index number by gpio number.
*
* @param gpio_num GPIO number
* @return
* >=0: Index of rtcio.
* -1 : The gpio is not rtcio.
*/
static inline int rtc_io_number_get(gpio_num_t gpio_num)
{
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
return rtc_io_num_map[gpio_num];
#else
return gpio_num;
#endif
}
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
/**
* @brief Init a GPIO as RTC GPIO
*
* This function must be called when initializing a pad for an analog function.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_init(gpio_num_t gpio_num);
/**
* @brief Init a GPIO as digital GPIO
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num);
/**
* @brief Get the RTC IO input level
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - 1 High level
* - 0 Low level
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
uint32_t rtc_gpio_get_level(gpio_num_t gpio_num);
/**
* @brief Set the RTC IO output level
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @param level output level
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_set_level(gpio_num_t gpio_num, uint32_t level);
/**
* @brief RTC GPIO set direction
*
* Configure RTC GPIO direction, such as output only, input only,
* output and input.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_set_direction(gpio_num_t gpio_num, rtc_gpio_mode_t mode);
/**
* @brief RTC GPIO set direction in deep sleep mode or disable sleep status (default).
* In some application scenarios, IO needs to have another states during deep sleep.
*
* NOTE: ESP32 support INPUT_ONLY mode.
* ESP32S2 support INPUT_ONLY, OUTPUT_ONLY, INPUT_OUTPUT mode.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @param mode GPIO direction
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_set_direction_in_sleep(gpio_num_t gpio_num, rtc_gpio_mode_t mode);
/**
* @brief RTC GPIO pullup enable
*
* This function only works for RTC IOs. In general, call gpio_pullup_en,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pullup_en(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pulldown enable
*
* This function only works for RTC IOs. In general, call gpio_pulldown_en,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pulldown_en(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pullup disable
*
* This function only works for RTC IOs. In general, call gpio_pullup_dis,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pullup_dis(gpio_num_t gpio_num);
/**
* @brief RTC GPIO pulldown disable
*
* This function only works for RTC IOs. In general, call gpio_pulldown_dis,
* which will work both for normal GPIOs and RTC IOs.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num);
/**
* @brief Set RTC GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t rtc_gpio_set_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t strength);
/**
* @brief Get RTC GPIO pad drive capability
*
* @param gpio_num GPIO number, only support output GPIOs
* @param strength Pointer to accept drive capability of the pad
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t rtc_gpio_get_drive_capability(gpio_num_t gpio_num, gpio_drive_cap_t* strength);
#endif // SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
#if SOC_RTCIO_HOLD_SUPPORTED
/**
* @brief Enable hold function on an RTC IO pad
*
* Enabling HOLD function will cause the pad to latch current values of
* input enable, output enable, 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 gpio_num GPIO number (e.g. GPIO_NUM_12)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num);
/**
* @brief Disable hold function on an RTC IO pad
*
* Disabling hold function will allow the pad receive the values of
* input enable, output enable, output value, function, drive strength from
* RTC_IO peripheral.
*
* @param gpio_num GPIO number (e.g. GPIO_NUM_12)
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num);
/**
* @brief 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 gpio_num GPIO number (e.g. GPIO_NUM_12).
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if GPIO is not an RTC IO
*/
esp_err_t rtc_gpio_isolate(gpio_num_t gpio_num);
/**
* @brief Enable force hold signal for all RTC IOs
*
* Each RTC pad has a "force hold" input signal from the RTC controller.
* If this signal is set, pad latches current values of input enable,
* function, output enable, and other signals which come from the RTC mux.
* Force hold signal is enabled before going into deep sleep for pins which
* are used for EXT1 wakeup.
*/
esp_err_t rtc_gpio_force_hold_all(void);
/**
* @brief Disable force hold signal for all RTC IOs
*/
esp_err_t rtc_gpio_force_hold_dis_all(void);
#endif // SOC_RTCIO_HOLD_SUPPORTED
#if SOC_RTCIO_WAKE_SUPPORTED
/**
* @brief Enable wakeup from sleep mode using specific GPIO
* @param gpio_num GPIO number
* @param intr_type Wakeup on high level (GPIO_INTR_HIGH_LEVEL) or low level
* (GPIO_INTR_LOW_LEVEL)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if gpio_num is not an RTC IO, or intr_type is not
* one of GPIO_INTR_HIGH_LEVEL, GPIO_INTR_LOW_LEVEL.
*/
esp_err_t rtc_gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type);
/**
* @brief Disable wakeup from sleep mode using specific GPIO
* @param gpio_num GPIO number
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if gpio_num is not an RTC IO
*/
esp_err_t rtc_gpio_wakeup_disable(gpio_num_t gpio_num);
#endif // SOC_RTCIO_WAKE_SUPPORTED
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,277 @@
// Copyright 2015-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.
#ifndef _DRIVER_SDIO_SLAVE_H_
#define _DRIVER_SDIO_SLAVE_H_
#include "freertos/FreeRTOS.h"
#include "esp_err.h"
#include "sys/queue.h"
#include "hal/sdio_slave_types.h"
#include "soc/sdio_slave_periph.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SDIO_SLAVE_RECV_MAX_BUFFER (4096-4)
typedef void(*sdio_event_cb_t)(uint8_t event);
/// Configuration of SDIO slave
typedef struct {
sdio_slave_timing_t timing; ///< timing of sdio_slave. see `sdio_slave_timing_t`.
sdio_slave_sending_mode_t sending_mode; ///< mode of sdio_slave. `SDIO_SLAVE_MODE_STREAM` if the data needs to be sent as much as possible; `SDIO_SLAVE_MODE_PACKET` if the data should be sent in packets.
int send_queue_size; ///< max buffers that can be queued before sending.
size_t recv_buffer_size;
///< If buffer_size is too small, it costs more CPU time to handle larger number of buffers.
///< If buffer_size is too large, the space larger than the transaction length is left blank but still counts a buffer, and the buffers are easily run out.
///< Should be set according to length of data really transferred.
///< All data that do not fully fill a buffer is still counted as one buffer. E.g. 10 bytes data costs 2 buffers if the size is 8 bytes per buffer.
///< Buffer size of the slave pre-defined between host and slave before communication. All receive buffer given to the driver should be larger than this.
sdio_event_cb_t event_cb; ///< when the host interrupts slave, this callback will be called with interrupt number (0-7).
uint32_t flags; ///< Features to be enabled for the slave, combinations of ``SDIO_SLAVE_FLAG_*``.
#define SDIO_SLAVE_FLAG_DAT2_DISABLED BIT(0) /**< It is required by the SD specification that all 4 data
lines should be used and pulled up even in 1-bit mode or SPI mode. However, as a feature, the user can specify
this flag to make use of DAT2 pin in 1-bit mode. Note that the host cannot read CCCR registers to know we don't
support 4-bit mode anymore, please do this at your own risk.
*/
#define SDIO_SLAVE_FLAG_HOST_INTR_DISABLED BIT(1) /**< The DAT1 line is used as the interrupt line in SDIO
protocol. However, as a feature, the user can specify this flag to make use of DAT1 pin of the slave in 1-bit
mode. Note that the host has to do polling to the interrupt registers to know whether there are interrupts from
the slave. And it cannot read CCCR registers to know we don't support 4-bit mode anymore, please do this at
your own risk.
*/
#define SDIO_SLAVE_FLAG_INTERNAL_PULLUP BIT(2) /**< Enable internal pullups for enabled pins. It is required
by the SD specification that all the 4 data lines should be pulled up even in 1-bit mode or SPI mode. Note that
the internal pull-ups are not sufficient for stable communication, please do connect external pull-ups on the
bus. This is only for example and debug use.
*/
} sdio_slave_config_t;
/** Handle of a receive buffer, register a handle by calling ``sdio_slave_recv_register_buf``. Use the handle to load the buffer to the
* driver, or call ``sdio_slave_recv_unregister_buf`` if it is no longer used.
*/
typedef void *sdio_slave_buf_handle_t;
/** Initialize the sdio slave driver
*
* @param config Configuration of the sdio slave driver.
*
* @return
* - ESP_ERR_NOT_FOUND if no free interrupt found.
* - ESP_ERR_INVALID_STATE if already initialized.
* - ESP_ERR_NO_MEM if fail due to memory allocation failed.
* - ESP_OK if success
*/
esp_err_t sdio_slave_initialize(sdio_slave_config_t *config);
/** De-initialize the sdio slave driver to release the resources.
*/
void sdio_slave_deinit(void);
/** Start hardware for sending and receiving, as well as set the IOREADY1 to 1.
*
* @note The driver will continue sending from previous data and PKT_LEN counting, keep data received as well as start receiving from current TOKEN1 counting.
* See ``sdio_slave_reset``.
*
* @return
* - ESP_ERR_INVALID_STATE if already started.
* - ESP_OK otherwise.
*/
esp_err_t sdio_slave_start(void);
/** Stop hardware from sending and receiving, also set IOREADY1 to 0.
*
* @note this will not clear the data already in the driver, and also not reset the PKT_LEN and TOKEN1 counting. Call ``sdio_slave_reset`` to do that.
*/
void sdio_slave_stop(void);
/** Clear the data still in the driver, as well as reset the PKT_LEN and TOKEN1 counting.
*
* @return always return ESP_OK.
*/
esp_err_t sdio_slave_reset(void);
/*---------------------------------------------------------------------------
* Receive
*--------------------------------------------------------------------------*/
/** Register buffer used for receiving. All buffers should be registered before used, and then can be used (again) in the driver by the handle returned.
*
* @param start The start address of the buffer.
*
* @note The driver will use and only use the amount of space specified in the `recv_buffer_size` member set in the `sdio_slave_config_t`.
* All buffers should be larger than that. The buffer is used by the DMA, so it should be DMA capable and 32-bit aligned.
*
* @return The buffer handle if success, otherwise NULL.
*/
sdio_slave_buf_handle_t sdio_slave_recv_register_buf(uint8_t *start);
/** Unregister buffer from driver, and free the space used by the descriptor pointing to the buffer.
*
* @param handle Handle to the buffer to release.
*
* @return ESP_OK if success, ESP_ERR_INVALID_ARG if the handle is NULL or the buffer is being used.
*/
esp_err_t sdio_slave_recv_unregister_buf(sdio_slave_buf_handle_t handle);
/** Load buffer to the queue waiting to receive data. The driver takes ownership of the buffer until the buffer is returned by
* ``sdio_slave_send_get_finished`` after the transaction is finished.
*
* @param handle Handle to the buffer ready to receive data.
*
* @return
* - ESP_ERR_INVALID_ARG if invalid handle or the buffer is already in the queue. Only after the buffer is returened by
* ``sdio_slave_recv`` can you load it again.
* - ESP_OK if success
*/
esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle);
/** Get received data if exist. The driver returns the ownership of the buffer to the app.
*
* @param handle_ret Handle to the buffer holding received data. Use this handle in ``sdio_slave_recv_load_buf`` to receive in the same buffer again.
* @param[out] out_addr Output of the start address, set to NULL if not needed.
* @param[out] out_len Actual length of the data in the buffer, set to NULL if not needed.
* @param wait Time to wait before data received.
*
* @note Call ``sdio_slave_load_buf`` with the handle to re-load the buffer onto the link list, and receive with the same buffer again.
* The address and length of the buffer got here is the same as got from `sdio_slave_get_buffer`.
*
* @return
* - ESP_ERR_INVALID_ARG if handle_ret is NULL
* - ESP_ERR_TIMEOUT if timeout before receiving new data
* - ESP_OK if success
*/
esp_err_t sdio_slave_recv(sdio_slave_buf_handle_t* handle_ret, uint8_t **out_addr, size_t *out_len, TickType_t wait);
/** Retrieve the buffer corresponding to a handle.
*
* @param handle Handle to get the buffer.
* @param len_o Output of buffer length
*
* @return buffer address if success, otherwise NULL.
*/
uint8_t* sdio_slave_recv_get_buf(sdio_slave_buf_handle_t handle, size_t *len_o);
/*---------------------------------------------------------------------------
* Send
*--------------------------------------------------------------------------*/
/** Put a new sending transfer into the send queue. The driver takes ownership of the buffer until the buffer is returned by
* ``sdio_slave_send_get_finished`` after the transaction is finished.
*
* @param addr Address for data to be sent. The buffer should be DMA capable and 32-bit aligned.
* @param len Length of the data, should not be longer than 4092 bytes (may support longer in the future).
* @param arg Argument to returned in ``sdio_slave_send_get_finished``. The argument can be used to indicate which transaction is done,
* or as a parameter for a callback. Set to NULL if not needed.
* @param wait Time to wait if the buffer is full.
*
* @return
* - ESP_ERR_INVALID_ARG if the length is not greater than 0.
* - ESP_ERR_TIMEOUT if the queue is still full until timeout.
* - ESP_OK if success.
*/
esp_err_t sdio_slave_send_queue(uint8_t* addr, size_t len, void* arg, TickType_t wait);
/** Return the ownership of a finished transaction.
* @param out_arg Argument of the finished transaction. Set to NULL if unused.
* @param wait Time to wait if there's no finished sending transaction.
*
* @return ESP_ERR_TIMEOUT if no transaction finished, or ESP_OK if succeed.
*/
esp_err_t sdio_slave_send_get_finished(void** out_arg, TickType_t wait);
/** Start a new sending transfer, and wait for it (blocked) to be finished.
*
* @param addr Start address of the buffer to send
* @param len Length of buffer to send.
*
* @return
* - ESP_ERR_INVALID_ARG if the length of descriptor is not greater than 0.
* - ESP_ERR_TIMEOUT if the queue is full or host do not start a transfer before timeout.
* - ESP_OK if success.
*/
esp_err_t sdio_slave_transmit(uint8_t* addr, size_t len);
/*---------------------------------------------------------------------------
* Host
*--------------------------------------------------------------------------*/
/** Read the spi slave register shared with host.
*
* @param pos register address, 0-27 or 32-63.
*
* @note register 28 to 31 are reserved for interrupt vector.
*
* @return value of the register.
*/
uint8_t sdio_slave_read_reg(int pos);
/** Write the spi slave register shared with host.
*
* @param pos register address, 0-11, 14-15, 18-19, 24-27 and 32-63, other address are reserved.
* @param reg the value to write.
*
* @note register 29 and 31 are used for interrupt vector.
*
* @return ESP_ERR_INVALID_ARG if address wrong, otherwise ESP_OK.
*/
esp_err_t sdio_slave_write_reg(int pos, uint8_t reg);
/** Get the interrupt enable for host.
*
* @return the interrupt mask.
*/
sdio_slave_hostint_t sdio_slave_get_host_intena(void);
/** Set the interrupt enable for host.
*
* @param mask Enable mask for host interrupt.
*/
void sdio_slave_set_host_intena(sdio_slave_hostint_t mask);
/** Interrupt the host by general purpose interrupt.
*
* @param pos Interrupt num, 0-7.
*
* @return
* - ESP_ERR_INVALID_ARG if interrupt num error
* - ESP_OK otherwise
*/
esp_err_t sdio_slave_send_host_int(uint8_t pos);
/** Clear general purpose interrupt to host.
*
* @param mask Interrupt bits to clear, by bit mask.
*/
void sdio_slave_clear_host_int(sdio_slave_hostint_t mask);
/** Wait for general purpose interrupt from host.
*
* @param pos Interrupt source number to wait for.
* is set.
* @param wait Time to wait before interrupt triggered.
*
* @note this clears the interrupt at the same time.
*
* @return ESP_OK if success, ESP_ERR_TIMEOUT if timeout.
*/
esp_err_t sdio_slave_wait_int(int pos, TickType_t wait);
#ifdef __cplusplus
}
#endif
#endif /*_DRIVER_SDIO_SLAVE_H */

View File

@ -0,0 +1,484 @@
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Adaptations to ESP-IDF Copyright (c) 2016 Espressif Systems (Shanghai) PTE LTD
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SDMMC_DEFS_H_
#define _SDMMC_DEFS_H_
#include <stdint.h>
#include <limits.h>
/* MMC commands */ /* response type */
#define MMC_GO_IDLE_STATE 0 /* R0 */
#define MMC_SEND_OP_COND 1 /* R3 */
#define MMC_ALL_SEND_CID 2 /* R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* R1 */
#define MMC_SWITCH 6 /* R1B */
#define MMC_SELECT_CARD 7 /* R1 */
#define MMC_SEND_EXT_CSD 8 /* R1 */
#define MMC_SEND_CSD 9 /* R2 */
#define MMC_SEND_CID 10 /* R1 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* R1 */
#define MMC_STOP_TRANSMISSION 12 /* R1B */
#define MMC_SEND_STATUS 13 /* R1 */
#define MMC_SET_BLOCKLEN 16 /* R1 */
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* R1 */
#define MMC_SET_BLOCK_COUNT 23 /* R1 */
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
#define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */
#define MMC_APP_CMD 55 /* R1 */
/* SD commands */ /* response type */
#define SD_SEND_RELATIVE_ADDR 3 /* R6 */
#define SD_SEND_SWITCH_FUNC 6 /* R1 */
#define SD_SEND_IF_COND 8 /* R7 */
#define SD_READ_OCR 58 /* R3 */
#define SD_CRC_ON_OFF 59 /* R1 */
/* SD application commands */ /* response type */
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
#define SD_APP_SD_STATUS 13 /* R2 */
#define SD_APP_OP_COND 41 /* R3 */
#define SD_APP_SEND_SCR 51 /* R1 */
/* SD IO commands */
#define SD_IO_SEND_OP_COND 5 /* R4 */
#define SD_IO_RW_DIRECT 52 /* R5 */
#define SD_IO_RW_EXTENDED 53 /* R5 */
/* OCR bits */
#define MMC_OCR_MEM_READY (1<<31) /* memory power-up status bit */
#define MMC_OCR_ACCESS_MODE_MASK 0x60000000 /* bits 30:29 */
#define MMC_OCR_SECTOR_MODE (1<<30)
#define MMC_OCR_BYTE_MODE (1<<29)
#define MMC_OCR_3_5V_3_6V (1<<23)
#define MMC_OCR_3_4V_3_5V (1<<22)
#define MMC_OCR_3_3V_3_4V (1<<21)
#define MMC_OCR_3_2V_3_3V (1<<20)
#define MMC_OCR_3_1V_3_2V (1<<19)
#define MMC_OCR_3_0V_3_1V (1<<18)
#define MMC_OCR_2_9V_3_0V (1<<17)
#define MMC_OCR_2_8V_2_9V (1<<16)
#define MMC_OCR_2_7V_2_8V (1<<15)
#define MMC_OCR_2_6V_2_7V (1<<14)
#define MMC_OCR_2_5V_2_6V (1<<13)
#define MMC_OCR_2_4V_2_5V (1<<12)
#define MMC_OCR_2_3V_2_4V (1<<11)
#define MMC_OCR_2_2V_2_3V (1<<10)
#define MMC_OCR_2_1V_2_2V (1<<9)
#define MMC_OCR_2_0V_2_1V (1<<8)
#define MMC_OCR_1_65V_1_95V (1<<7)
#define SD_OCR_SDHC_CAP (1<<30)
#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */
/* SD mode R1 response type bits */
#define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */
#define MMC_R1_APP_CMD (1<<5) /* app. commands supported */
#define MMC_R1_SWITCH_ERROR (1<<7) /* switch command did not succeed */
/* SPI mode R1 response type bits */
#define SD_SPI_R1_IDLE_STATE (1<<0)
#define SD_SPI_R1_ERASE_RST (1<<1)
#define SD_SPI_R1_ILLEGAL_CMD (1<<2)
#define SD_SPI_R1_CMD_CRC_ERR (1<<3)
#define SD_SPI_R1_ERASE_SEQ_ERR (1<<4)
#define SD_SPI_R1_ADDR_ERR (1<<5)
#define SD_SPI_R1_PARAM_ERR (1<<6)
#define SD_SPI_R1_NO_RESPONSE (1<<7)
#define SDIO_R1_FUNC_NUM_ERR (1<<4)
/* 48-bit response decoding (32 bits w/o CRC) */
#define MMC_R1(resp) ((resp)[0])
#define MMC_R3(resp) ((resp)[0])
#define MMC_R4(resp) ((resp)[0])
#define MMC_R5(resp) ((resp)[0])
#define SD_R6(resp) ((resp)[0])
#define MMC_R1_CURRENT_STATE(resp) (((resp)[0] >> 9) & 0xf)
/* SPI mode response decoding */
#define SD_SPI_R1(resp) ((resp)[0] & 0xff)
#define SD_SPI_R2(resp) ((resp)[0] & 0xffff)
#define SD_SPI_R3(resp) ((resp)[0])
#define SD_SPI_R7(resp) ((resp)[0])
/* SPI mode data response decoding */
#define SD_SPI_DATA_RSP_VALID(resp_byte) (((resp_byte)&0x11)==0x1)
#define SD_SPI_DATA_RSP(resp_byte) (((resp_byte)>>1)&0x7)
#define SD_SPI_DATA_ACCEPTED 0x2
#define SD_SPI_DATA_CRC_ERROR 0x5
#define SD_SPI_DATA_WR_ERROR 0x6
/* RCA argument and response */
#define MMC_ARG_RCA(rca) ((rca) << 16)
#define SD_R6_RCA(resp) (SD_R6((resp)) >> 16)
/* bus width argument */
#define SD_ARG_BUS_WIDTH_1 0
#define SD_ARG_BUS_WIDTH_4 2
/* EXT_CSD fields */
#define EXT_CSD_BUS_WIDTH 183 /* WO */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_SEC_COUNT 212 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_CMD_SET 191 /* R/W */
#define EXT_CSD_S_CMD_SET 504 /* RO */
/* EXT_CSD field definitions */
#define EXT_CSD_CMD_SET_NORMAL (1U << 0)
#define EXT_CSD_CMD_SET_SECURE (1U << 1)
#define EXT_CSD_CMD_SET_CPSECURE (1U << 2)
/* EXT_CSD_HS_TIMING */
#define EXT_CSD_HS_TIMING_BC 0
#define EXT_CSD_HS_TIMING_HS 1
#define EXT_CSD_HS_TIMING_HS200 2
#define EXT_CSD_HS_TIMING_HS400 3
/* EXT_CSD_BUS_WIDTH */
#define EXT_CSD_BUS_WIDTH_1 0
#define EXT_CSD_BUS_WIDTH_4 1
#define EXT_CSD_BUS_WIDTH_8 2
#define EXT_CSD_BUS_WIDTH_4_DDR 5
#define EXT_CSD_BUS_WIDTH_8_DDR 6
/* EXT_CSD_CARD_TYPE */
/* The only currently valid values for this field are 0x01, 0x03, 0x07,
* 0x0B and 0x0F. */
#define EXT_CSD_CARD_TYPE_F_26M (1 << 0) /* SDR at "rated voltages */
#define EXT_CSD_CARD_TYPE_F_52M (1 << 1) /* SDR at "rated voltages */
#define EXT_CSD_CARD_TYPE_F_52M_1_8V (1 << 2) /* DDR, 1.8V or 3.3V I/O */
#define EXT_CSD_CARD_TYPE_F_52M_1_2V (1 << 3) /* DDR, 1.2V I/O */
#define EXT_CSD_CARD_TYPE_26M 0x01
#define EXT_CSD_CARD_TYPE_52M 0x03
#define EXT_CSD_CARD_TYPE_52M_V18 0x07
#define EXT_CSD_CARD_TYPE_52M_V12 0x0b
#define EXT_CSD_CARD_TYPE_52M_V12_18 0x0f
/* EXT_CSD MMC */
#define EXT_CSD_MMC_SIZE 512
/* MMC_SWITCH access mode */
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/* MMC R2 response (CSD) */
#define MMC_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define MMC_CSD_CSDVER_1_0 1
#define MMC_CSD_CSDVER_2_0 2
#define MMC_CSD_CSDVER_EXT_CSD 3
#define MMC_CSD_MMCVER(resp) MMC_RSP_BITS((resp), 122, 4)
#define MMC_CSD_MMCVER_1_0 0 /* MMC 1.0 - 1.2 */
#define MMC_CSD_MMCVER_1_4 1 /* MMC 1.4 */
#define MMC_CSD_MMCVER_2_0 2 /* MMC 2.0 - 2.2 */
#define MMC_CSD_MMCVER_3_1 3 /* MMC 3.1 - 3.3 */
#define MMC_CSD_MMCVER_4_0 4 /* MMC 4 */
#define MMC_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define MMC_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define MMC_CSD_CAPACITY(resp) ((MMC_CSD_C_SIZE((resp))+1) << \
(MMC_CSD_C_SIZE_MULT((resp))+2))
#define MMC_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
/* MMC v1 R2 response (CID) */
#define MMC_CID_MID_V1(resp) MMC_RSP_BITS((resp), 104, 24)
#define MMC_CID_PNM_V1_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = MMC_RSP_BITS((resp), 48, 8); \
(pnm)[7] = '\0'; \
} while (0)
#define MMC_CID_REV_V1(resp) MMC_RSP_BITS((resp), 40, 8)
#define MMC_CID_PSN_V1(resp) MMC_RSP_BITS((resp), 16, 24)
#define MMC_CID_MDT_V1(resp) MMC_RSP_BITS((resp), 8, 8)
/* MMC v2 R2 response (CID) */
#define MMC_CID_MID_V2(resp) MMC_RSP_BITS((resp), 120, 8)
#define MMC_CID_OID_V2(resp) MMC_RSP_BITS((resp), 104, 16)
#define MMC_CID_PNM_V2_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = MMC_RSP_BITS((resp), 56, 8); \
(pnm)[6] = '\0'; \
} while (0)
#define MMC_CID_PSN_V2(resp) MMC_RSP_BITS((resp), 16, 32)
/* SD R2 response (CSD) */
#define SD_CSD_CSDVER(resp) MMC_RSP_BITS((resp), 126, 2)
#define SD_CSD_CSDVER_1_0 0
#define SD_CSD_CSDVER_2_0 1
#define SD_CSD_TAAC(resp) MMC_RSP_BITS((resp), 112, 8)
#define SD_CSD_TAAC_1_5_MSEC 0x26
#define SD_CSD_NSAC(resp) MMC_RSP_BITS((resp), 104, 8)
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
#define SD_CSD_SPEED_25_MHZ 0x32
#define SD_CSD_SPEED_50_MHZ 0x5a
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
#define SD_CSD_CCC_BASIC (1 << 0) /* basic */
#define SD_CSD_CCC_BR (1 << 2) /* block read */
#define SD_CSD_CCC_BW (1 << 4) /* block write */
#define SD_CSD_CCC_ERASE (1 << 5) /* erase */
#define SD_CSD_CCC_WP (1 << 6) /* write protection */
#define SD_CSD_CCC_LC (1 << 7) /* lock card */
#define SD_CSD_CCC_AS (1 << 8) /*application specific*/
#define SD_CSD_CCC_IOM (1 << 9) /* I/O mode */
#define SD_CSD_CCC_SWITCH (1 << 10) /* switch */
#define SD_CSD_READ_BL_LEN(resp) MMC_RSP_BITS((resp), 80, 4)
#define SD_CSD_READ_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 79, 1)
#define SD_CSD_WRITE_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 78, 1)
#define SD_CSD_READ_BLK_MISALIGN(resp) MMC_RSP_BITS((resp), 77, 1)
#define SD_CSD_DSR_IMP(resp) MMC_RSP_BITS((resp), 76, 1)
#define SD_CSD_C_SIZE(resp) MMC_RSP_BITS((resp), 62, 12)
#define SD_CSD_CAPACITY(resp) ((SD_CSD_C_SIZE((resp))+1) << \
(SD_CSD_C_SIZE_MULT((resp))+2))
#define SD_CSD_V2_C_SIZE(resp) MMC_RSP_BITS((resp), 48, 22)
#define SD_CSD_V2_CAPACITY(resp) ((SD_CSD_V2_C_SIZE((resp))+1) << 10)
#define SD_CSD_V2_BL_LEN 0x9 /* 512 */
#define SD_CSD_VDD_R_CURR_MIN(resp) MMC_RSP_BITS((resp), 59, 3)
#define SD_CSD_VDD_R_CURR_MAX(resp) MMC_RSP_BITS((resp), 56, 3)
#define SD_CSD_VDD_W_CURR_MIN(resp) MMC_RSP_BITS((resp), 53, 3)
#define SD_CSD_VDD_W_CURR_MAX(resp) MMC_RSP_BITS((resp), 50, 3)
#define SD_CSD_VDD_RW_CURR_100mA 0x7
#define SD_CSD_VDD_RW_CURR_80mA 0x6
#define SD_CSD_C_SIZE_MULT(resp) MMC_RSP_BITS((resp), 47, 3)
#define SD_CSD_ERASE_BLK_EN(resp) MMC_RSP_BITS((resp), 46, 1)
#define SD_CSD_SECTOR_SIZE(resp) MMC_RSP_BITS((resp), 39, 7) /* +1 */
#define SD_CSD_WP_GRP_SIZE(resp) MMC_RSP_BITS((resp), 32, 7) /* +1 */
#define SD_CSD_WP_GRP_ENABLE(resp) MMC_RSP_BITS((resp), 31, 1)
#define SD_CSD_R2W_FACTOR(resp) MMC_RSP_BITS((resp), 26, 3)
#define SD_CSD_WRITE_BL_LEN(resp) MMC_RSP_BITS((resp), 22, 4)
#define SD_CSD_RW_BL_LEN_2G 0xa
#define SD_CSD_RW_BL_LEN_1G 0x9
#define SD_CSD_WRITE_BL_PARTIAL(resp) MMC_RSP_BITS((resp), 21, 1)
#define SD_CSD_FILE_FORMAT_GRP(resp) MMC_RSP_BITS((resp), 15, 1)
#define SD_CSD_COPY(resp) MMC_RSP_BITS((resp), 14, 1)
#define SD_CSD_PERM_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 13, 1)
#define SD_CSD_TMP_WRITE_PROTECT(resp) MMC_RSP_BITS((resp), 12, 1)
#define SD_CSD_FILE_FORMAT(resp) MMC_RSP_BITS((resp), 10, 2)
/* SD R2 response (CID) */
#define SD_CID_MID(resp) MMC_RSP_BITS((resp), 120, 8)
#define SD_CID_OID(resp) MMC_RSP_BITS((resp), 104, 16)
#define SD_CID_PNM_CPY(resp, pnm) \
do { \
(pnm)[0] = MMC_RSP_BITS((resp), 96, 8); \
(pnm)[1] = MMC_RSP_BITS((resp), 88, 8); \
(pnm)[2] = MMC_RSP_BITS((resp), 80, 8); \
(pnm)[3] = MMC_RSP_BITS((resp), 72, 8); \
(pnm)[4] = MMC_RSP_BITS((resp), 64, 8); \
(pnm)[5] = '\0'; \
} while (0)
#define SD_CID_REV(resp) MMC_RSP_BITS((resp), 56, 8)
#define SD_CID_PSN(resp) MMC_RSP_BITS((resp), 24, 32)
#define SD_CID_MDT(resp) MMC_RSP_BITS((resp), 8, 12)
/* SCR (SD Configuration Register) */
#define SCR_STRUCTURE(scr) MMC_RSP_BITS((scr), 60, 4)
#define SCR_STRUCTURE_VER_1_0 0 /* Version 1.0 */
#define SCR_SD_SPEC(scr) MMC_RSP_BITS((scr), 56, 4)
#define SCR_SD_SPEC_VER_1_0 0 /* Version 1.0 and 1.01 */
#define SCR_SD_SPEC_VER_1_10 1 /* Version 1.10 */
#define SCR_SD_SPEC_VER_2 2 /* Version 2.00 or Version 3.0X */
#define SCR_DATA_STAT_AFTER_ERASE(scr) MMC_RSP_BITS((scr), 55, 1)
#define SCR_SD_SECURITY(scr) MMC_RSP_BITS((scr), 52, 3)
#define SCR_SD_SECURITY_NONE 0 /* no security */
#define SCR_SD_SECURITY_1_0 1 /* security protocol 1.0 */
#define SCR_SD_SECURITY_1_0_2 2 /* security protocol 1.0 */
#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4)
#define SCR_SD_BUS_WIDTHS_1BIT (1 << 0) /* 1bit (DAT0) */
#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */
#define SCR_SD_SPEC3(scr) MMC_RSP_BITS((scr), 47, 1)
#define SCR_EX_SECURITY(scr) MMC_RSP_BITS((scr), 43, 4)
#define SCR_SD_SPEC4(scr) MMC_RSP_BITS((scr), 42, 1)
#define SCR_RESERVED(scr) MMC_RSP_BITS((scr), 34, 8)
#define SCR_CMD_SUPPORT_CMD23(scr) MMC_RSP_BITS((scr), 33, 1)
#define SCR_CMD_SUPPORT_CMD20(scr) MMC_RSP_BITS((scr), 32, 1)
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
/* Max supply current in SWITCH_FUNC response (in mA) */
#define SD_SFUNC_I_MAX(status) (MMC_RSP_BITS((uint32_t *)(status), 496, 16))
/* Supported flags in SWITCH_FUNC response */
#define SD_SFUNC_SUPPORTED(status, group) \
(MMC_RSP_BITS((uint32_t *)(status), 400 + (group - 1) * 16, 16))
/* Selected function in SWITCH_FUNC response */
#define SD_SFUNC_SELECTED(status, group) \
(MMC_RSP_BITS((uint32_t *)(status), 376 + (group - 1) * 4, 4))
/* Busy flags in SWITCH_FUNC response */
#define SD_SFUNC_BUSY(status, group) \
(MMC_RSP_BITS((uint32_t *)(status), 272 + (group - 1) * 16, 16))
/* Version of SWITCH_FUNC response */
#define SD_SFUNC_VER(status) (MMC_RSP_BITS((uint32_t *)(status), 368, 8))
#define SD_SFUNC_GROUP_MAX 6
#define SD_SFUNC_FUNC_MAX 15
#define SD_ACCESS_MODE 1 /* Function group 1, Access Mode */
#define SD_ACCESS_MODE_SDR12 0 /* 25 MHz clock */
#define SD_ACCESS_MODE_SDR25 1 /* 50 MHz clock */
#define SD_ACCESS_MODE_SDR50 2 /* UHS-I, 100 MHz clock */
#define SD_ACCESS_MODE_SDR104 3 /* UHS-I, 208 MHz clock */
#define SD_ACCESS_MODE_DDR50 4 /* UHS-I, 50 MHz clock, DDR */
/**
* @brief Extract up to 32 sequential bits from an array of 32-bit words
*
* Bits within the word are numbered in the increasing order from LSB to MSB.
*
* As an example, consider 2 32-bit words:
*
* 0x01234567 0x89abcdef
*
* On a little-endian system, the bytes are stored in memory as follows:
*
* 67 45 23 01 ef cd ab 89
*
* MMC_RSP_BITS will extact bits as follows:
*
* start=0 len=4 -> result=0x00000007
* start=0 len=12 -> result=0x00000567
* start=28 len=8 -> result=0x000000f0
* start=59 len=5 -> result=0x00000011
*
* @param src array of words to extract bits from
* @param start index of the first bit to extract
* @param len number of bits to extract, 1 to 32
* @return 32-bit word where requested bits start from LSB
*/
static inline uint32_t MMC_RSP_BITS(uint32_t *src, int start, int len)
{
uint32_t mask = (len % 32 == 0) ? UINT_MAX : UINT_MAX >> (32 - (len % 32));
size_t word = start / 32;
size_t shift = start % 32;
uint32_t right = src[word] >> shift;
uint32_t left = (len + shift <= 32) ? 0 : src[word + 1] << ((32 - shift) % 32);
return (left | right) & mask;
}
/* SD R4 response (IO OCR) */
#define SD_IO_OCR_MEM_READY (1<<31)
#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x7)
#define SD_IO_OCR_MEM_PRESENT (1<<27)
#define SD_IO_OCR_MASK 0x00fffff0
/* CMD52 arguments */
#define SD_ARG_CMD52_READ (0<<31)
#define SD_ARG_CMD52_WRITE (1<<31)
#define SD_ARG_CMD52_FUNC_SHIFT 28
#define SD_ARG_CMD52_FUNC_MASK 0x7
#define SD_ARG_CMD52_EXCHANGE (1<<27)
#define SD_ARG_CMD52_REG_SHIFT 9
#define SD_ARG_CMD52_REG_MASK 0x1ffff
#define SD_ARG_CMD52_DATA_SHIFT 0
#define SD_ARG_CMD52_DATA_MASK 0xff
#define SD_R5_DATA(resp) ((resp)[0] & 0xff)
/* CMD53 arguments */
#define SD_ARG_CMD53_READ (0<<31)
#define SD_ARG_CMD53_WRITE (1<<31)
#define SD_ARG_CMD53_FUNC_SHIFT 28
#define SD_ARG_CMD53_FUNC_MASK 0x7
#define SD_ARG_CMD53_BLOCK_MODE (1<<27)
#define SD_ARG_CMD53_INCREMENT (1<<26)
#define SD_ARG_CMD53_REG_SHIFT 9
#define SD_ARG_CMD53_REG_MASK 0x1ffff
#define SD_ARG_CMD53_LENGTH_SHIFT 0
#define SD_ARG_CMD53_LENGTH_MASK 0x1ff
#define SD_ARG_CMD53_LENGTH_MAX 512
/* Card Common Control Registers (CCCR) */
#define SD_IO_CCCR_START 0x00000
#define SD_IO_CCCR_SIZE 0x100
#define SD_IO_CCCR_FN_ENABLE 0x02
#define SD_IO_CCCR_FN_READY 0x03
#define SD_IO_CCCR_INT_ENABLE 0x04
#define SD_IO_CCCR_INT_PENDING 0x05
#define SD_IO_CCCR_CTL 0x06
#define CCCR_CTL_RES (1<<3)
#define SD_IO_CCCR_BUS_WIDTH 0x07
#define CCCR_BUS_WIDTH_1 (0<<0)
#define CCCR_BUS_WIDTH_4 (2<<0)
#define CCCR_BUS_WIDTH_8 (3<<0)
#define CCCR_BUS_WIDTH_ECSI (1<<5)
#define SD_IO_CCCR_CARD_CAP 0x08
#define CCCR_CARD_CAP_LSC BIT(6)
#define CCCR_CARD_CAP_4BLS BIT(7)
#define SD_IO_CCCR_CISPTR 0x09
#define SD_IO_CCCR_BLKSIZEL 0x10
#define SD_IO_CCCR_BLKSIZEH 0x11
#define SD_IO_CCCR_HIGHSPEED 0x13
#define CCCR_HIGHSPEED_SUPPORT BIT(0)
#define CCCR_HIGHSPEED_ENABLE BIT(1)
/* Function Basic Registers (FBR) */
#define SD_IO_FBR_START 0x00100
#define SD_IO_FBR_SIZE 0x00700
/* Card Information Structure (CIS) */
#define SD_IO_CIS_START 0x01000
#define SD_IO_CIS_SIZE 0x17000
/* CIS tuple codes (based on PC Card 16) */
#define CISTPL_CODE_NULL 0x00
#define CISTPL_CODE_DEVICE 0x01
#define CISTPL_CODE_CHKSUM 0x10
#define CISTPL_CODE_VERS1 0x15
#define CISTPL_CODE_ALTSTR 0x16
#define CISTPL_CODE_CONFIG 0x1A
#define CISTPL_CODE_CFTABLE_ENTRY 0x1B
#define CISTPL_CODE_MANFID 0x20
#define CISTPL_CODE_FUNCID 0x21
#define TPLFID_FUNCTION_SDIO 0x0c
#define CISTPL_CODE_FUNCE 0x22
#define CISTPL_CODE_VENDER_BEGIN 0x80
#define CISTPL_CODE_VENDER_END 0x8F
#define CISTPL_CODE_SDIO_STD 0x91
#define CISTPL_CODE_SDIO_EXT 0x92
#define CISTPL_CODE_END 0xFF
/* Timing */
#define SDMMC_TIMING_LEGACY 0
#define SDMMC_TIMING_HIGHSPEED 1
#define SDMMC_TIMING_MMC_DDR52 2
#endif //_SDMMC_DEFS_H_

View File

@ -0,0 +1,247 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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"
#if SOC_SDMMC_HOST_SUPPORTED
#include <stdint.h>
#include <stddef.h>
#include "esp_err.h"
#include "sdmmc_types.h"
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SDMMC_HOST_SLOT_0 0 ///< SDMMC slot 0
#define SDMMC_HOST_SLOT_1 1 ///< SDMMC slot 1
/**
* @brief Default sdmmc_host_t structure initializer for SDMMC peripheral
*
* Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz
*/
#define SDMMC_HOST_DEFAULT() {\
.flags = SDMMC_HOST_FLAG_8BIT | \
SDMMC_HOST_FLAG_4BIT | \
SDMMC_HOST_FLAG_1BIT | \
SDMMC_HOST_FLAG_DDR, \
.slot = SDMMC_HOST_SLOT_1, \
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
.io_voltage = 3.3f, \
.init = &sdmmc_host_init, \
.set_bus_width = &sdmmc_host_set_bus_width, \
.get_bus_width = &sdmmc_host_get_slot_width, \
.set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
.set_card_clk = &sdmmc_host_set_card_clk, \
.do_transaction = &sdmmc_host_do_transaction, \
.deinit = &sdmmc_host_deinit, \
.io_int_enable = sdmmc_host_io_int_enable, \
.io_int_wait = sdmmc_host_io_int_wait, \
.command_timeout_ms = 0, \
}
/**
* Extra configuration for SDMMC peripheral slot
*/
typedef struct {
gpio_num_t gpio_cd; ///< GPIO number of card detect signal
gpio_num_t gpio_wp; ///< GPIO number of write protect signal
uint8_t width; ///< Bus width used by the slot (might be less than the max width supported)
uint32_t flags; ///< Features used by this slot
#define SDMMC_SLOT_FLAG_INTERNAL_PULLUP BIT(0)
/**< Enable internal pullups on enabled pins. The internal pullups
are insufficient however, please make sure external pullups are
connected on the bus. This is for debug / example purpose only.
*/
} sdmmc_slot_config_t;
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used
#define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used
#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the default width for the slot (8 for slot 0, 4 for slot 1)
/**
* Macro defining default configuration of SDMMC host slot
*/
#define SDMMC_SLOT_CONFIG_DEFAULT() {\
.gpio_cd = SDMMC_SLOT_NO_CD, \
.gpio_wp = SDMMC_SLOT_NO_WP, \
.width = SDMMC_SLOT_WIDTH_DEFAULT, \
.flags = 0, \
}
/**
* @brief Initialize SDMMC host peripheral
*
* @note This function is not thread safe
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
*/
esp_err_t sdmmc_host_init(void);
/**
* @brief Initialize given slot of SDMMC peripheral
*
* On the ESP32, SDMMC peripheral has two slots:
* - Slot 0: 8-bit wide, maps to HS1_* signals in PIN MUX
* - Slot 1: 4-bit wide, maps to HS2_* signals in PIN MUX
*
* Card detect and write protect signals can be routed to
* arbitrary GPIOs using GPIO matrix.
*
* @note This function is not thread safe
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param slot_config additional configuration for the slot
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if host has not been initialized using sdmmc_host_init
*/
esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config);
/**
* @brief Select bus width to be used for data transfer
*
* SD/MMC card must be initialized prior to this command, and a command to set
* bus width has to be sent to the card (e.g. SD_APP_SET_BUS_WIDTH)
*
* @note This function is not thread safe
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param width bus width (1, 4, or 8 for slot 0; 1 or 4 for slot 1)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if slot number or width is not valid
*/
esp_err_t sdmmc_host_set_bus_width(int slot, size_t width);
/**
* @brief Get bus width configured in ``sdmmc_host_init_slot`` to be used for data transfer
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @return configured bus width of the specified slot.
*/
size_t sdmmc_host_get_slot_width(int slot);
/**
* @brief Set card clock frequency
*
* Currently only integer fractions of 40MHz clock can be used.
* For High Speed cards, 40MHz can be used.
* For Default Speed cards, 20MHz can be used.
*
* @note This function is not thread safe
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param freq_khz card clock frequency, in kHz
* @return
* - ESP_OK on success
* - other error codes may be returned in the future
*/
esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz);
/**
* @brief Enable or disable DDR mode of SD interface
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param ddr_enabled enable or disable DDR mode
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_SUPPORTED if DDR mode is not supported on this slot
*/
esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled);
/**
* @brief Send command to the card and get response
*
* This function returns when command is sent and response is received,
* or data is transferred, or timeout occurs.
*
* @note This function is not thread safe w.r.t. init/deinit functions,
* and bus width/clock speed configuration functions. Multiple tasks
* can call sdmmc_host_do_transaction as long as other sdmmc_host_*
* functions are not called.
*
* @attention Data buffer passed in cmdinfo->data must be in DMA capable memory
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param cmdinfo pointer to structure describing command and data to transfer
* @return
* - ESP_OK on success
* - ESP_ERR_TIMEOUT if response or data transfer has timed out
* - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
* - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
* - ESP_ERR_INVALID_SIZE if the size of data transfer is not valid in SD protocol
* - ESP_ERR_INVALID_ARG if the data buffer is not in DMA capable memory
*/
esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo);
/**
* @brief Enable IO interrupts
*
* This function configures the host to accept SDIO interrupts.
*
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @return returns ESP_OK, other errors possible in the future
*/
esp_err_t sdmmc_host_io_int_enable(int slot);
/**
* @brief Block until an SDIO interrupt is received, or timeout occurs
* @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
* @param timeout_ticks number of RTOS ticks to wait for the interrupt
* @return
* - ESP_OK on success (interrupt received)
* - ESP_ERR_TIMEOUT if the interrupt did not occur within timeout_ticks
*/
esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks);
/**
* @brief Disable SDMMC host and release allocated resources
*
* @note This function is not thread safe
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called
*/
esp_err_t sdmmc_host_deinit(void);
/**
* @brief Enable the pull-ups of sd pins.
*
* @note You should always place actual pullups on the lines instead of using
* this function. Internal pullup resistance are high and not sufficient, may
* cause instability in products. This is for debug or examples only.
*
* @param slot Slot to use, normally set it to 1.
* @param width Bit width of your configuration, 1 or 4.
*
* @return
* - ESP_OK: if success
* - ESP_ERR_INVALID_ARG: if configured width larger than maximum the slot can
* support
*/
esp_err_t sdmmc_host_pullup_en(int slot, int width);
#ifdef __cplusplus
}
#endif
#endif //SOC_SDMMC_HOST_SUPPORTED

View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
* Adaptations to ESP-IDF Copyright (c) 2016 Espressif Systems (Shanghai) PTE LTD
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SDMMC_TYPES_H_
#define _SDMMC_TYPES_H_
#include <stdint.h>
#include <stddef.h>
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
/**
* Decoded values from SD card Card Specific Data register
*/
typedef struct {
int csd_ver; /*!< CSD structure format */
int mmc_ver; /*!< MMC version (for CID format) */
int capacity; /*!< total number of sectors */
int sector_size; /*!< sector size in bytes */
int read_block_len; /*!< block length for reads */
int card_command_class; /*!< Card Command Class for SD */
int tr_speed; /*!< Max transfer speed */
} sdmmc_csd_t;
/**
* Decoded values from SD card Card IDentification register
*/
typedef struct {
int mfg_id; /*!< manufacturer identification number */
int oem_id; /*!< OEM/product identification number */
char name[8]; /*!< product name (MMC v1 has the longest) */
int revision; /*!< product revision */
int serial; /*!< product serial number */
int date; /*!< manufacturing date */
} sdmmc_cid_t;
/**
* Decoded values from SD Configuration Register
*/
typedef struct {
int sd_spec; /*!< SD Physical layer specification version, reported by card */
int bus_width; /*!< bus widths supported by card: BIT(0) — 1-bit bus, BIT(2) — 4-bit bus */
} sdmmc_scr_t;
/**
* Decoded values of Extended Card Specific Data
*/
typedef struct {
uint8_t power_class; /*!< Power class used by the card */
} sdmmc_ext_csd_t;
/**
* SD/MMC command response buffer
*/
typedef uint32_t sdmmc_response_t[4];
/**
* SD SWITCH_FUNC response buffer
*/
typedef struct {
uint32_t data[512 / 8 / sizeof(uint32_t)]; /*!< response data */
} sdmmc_switch_func_rsp_t;
/**
* SD/MMC command information
*/
typedef struct {
uint32_t opcode; /*!< SD or MMC command index */
uint32_t arg; /*!< SD/MMC command argument */
sdmmc_response_t response; /*!< response buffer */
void* data; /*!< buffer to send or read into */
size_t datalen; /*!< length of data buffer */
size_t blklen; /*!< block length */
int flags; /*!< see below */
/** @cond */
#define SCF_ITSDONE 0x0001 /*!< command is complete */
#define SCF_CMD(flags) ((flags) & 0x00f0)
#define SCF_CMD_AC 0x0000
#define SCF_CMD_ADTC 0x0010
#define SCF_CMD_BC 0x0020
#define SCF_CMD_BCR 0x0030
#define SCF_CMD_READ 0x0040 /*!< read command (data expected) */
#define SCF_RSP_BSY 0x0100
#define SCF_RSP_136 0x0200
#define SCF_RSP_CRC 0x0400
#define SCF_RSP_IDX 0x0800
#define SCF_RSP_PRESENT 0x1000
/* response types */
#define SCF_RSP_R0 0 /*!< none */
#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136)
#define SCF_RSP_R3 (SCF_RSP_PRESENT)
#define SCF_RSP_R4 (SCF_RSP_PRESENT)
#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY)
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
/* special flags */
#define SCF_WAIT_BUSY 0x2000 /*!< Wait for completion of card busy signal before returning */
/** @endcond */
esp_err_t error; /*!< error returned from transfer */
int timeout_ms; /*!< response timeout, in milliseconds */
} sdmmc_command_t;
/**
* SD/MMC Host description
*
* This structure defines properties of SD/MMC host and functions
* of SD/MMC host which can be used by upper layers.
*/
typedef struct {
uint32_t flags; /*!< flags defining host properties */
#define SDMMC_HOST_FLAG_1BIT BIT(0) /*!< host supports 1-line SD and MMC protocol */
#define SDMMC_HOST_FLAG_4BIT BIT(1) /*!< host supports 4-line SD and MMC protocol */
#define SDMMC_HOST_FLAG_8BIT BIT(2) /*!< host supports 8-line MMC protocol */
#define SDMMC_HOST_FLAG_SPI BIT(3) /*!< host supports SPI protocol */
#define SDMMC_HOST_FLAG_DDR BIT(4) /*!< host supports DDR mode for SD/MMC */
#define SDMMC_HOST_FLAG_DEINIT_ARG BIT(5) /*!< host `deinit` function called with the slot argument */
int slot; /*!< slot number, to be passed to host functions */
int max_freq_khz; /*!< max frequency supported by the host */
#define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */
#define SDMMC_FREQ_HIGHSPEED 40000 /*!< SD High speed (limited by clock divider) */
#define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */
#define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */
#define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */
float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */
esp_err_t (*init)(void); /*!< Host function to initialize the driver */
esp_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */
size_t (*get_bus_width)(int slot); /*!< host function to get bus width */
esp_err_t (*set_bus_ddr_mode)(int slot, bool ddr_enable); /*!< host function to set DDR mode */
esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */
esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */
union {
esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */
esp_err_t (*deinit_p)(int slot); /*!< host function to deinitialize the driver, called with the `slot` */
};
esp_err_t (*io_int_enable)(int slot); /*!< Host function to enable SDIO interrupt line */
esp_err_t (*io_int_wait)(int slot, TickType_t timeout_ticks); /*!< Host function to wait for SDIO interrupt line to be active */
int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */
} sdmmc_host_t;
/**
* SD/MMC card information structure
*/
typedef struct {
sdmmc_host_t host; /*!< Host with which the card is associated */
uint32_t ocr; /*!< OCR (Operation Conditions Register) value */
union {
sdmmc_cid_t cid; /*!< decoded CID (Card IDentification) register value */
sdmmc_response_t raw_cid; /*!< raw CID of MMC card to be decoded
after the CSD is fetched in the data transfer mode*/
};
sdmmc_csd_t csd; /*!< decoded CSD (Card-Specific Data) register value */
sdmmc_scr_t scr; /*!< decoded SCR (SD card Configuration Register) value */
sdmmc_ext_csd_t ext_csd; /*!< decoded EXT_CSD (Extended Card Specific Data) register value */
uint16_t rca; /*!< RCA (Relative Card Address) */
uint16_t max_freq_khz; /*!< Maximum frequency, in kHz, supported by the card */
uint32_t is_mem : 1; /*!< Bit indicates if the card is a memory card */
uint32_t is_sdio : 1; /*!< Bit indicates if the card is an IO card */
uint32_t is_mmc : 1; /*!< Bit indicates if the card is MMC */
uint32_t num_io_functions : 3; /*!< If is_sdio is 1, contains the number of IO functions on the card */
uint32_t log_bus_width : 2; /*!< log2(bus width supported by card) */
uint32_t is_ddr : 1; /*!< Card supports DDR mode */
uint32_t reserved : 23; /*!< Reserved for future expansion */
} sdmmc_card_t;
#endif // _SDMMC_TYPES_H_

View File

@ -0,0 +1,246 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 <stddef.h>
#include "esp_err.h"
#include "sdmmc_types.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#ifdef __cplusplus
extern "C" {
#endif
/// Handle representing an SD SPI device
typedef int sdspi_dev_handle_t;
/**
* @brief Default sdmmc_host_t structure initializer for SD over SPI driver
*
* Uses SPI mode and max frequency set to 20MHz
*
* 'slot' should be set to an sdspi device initialized by `sdspi_host_init_device()`.
*/
#define SDSPI_HOST_DEFAULT() {\
.flags = SDMMC_HOST_FLAG_SPI | SDMMC_HOST_FLAG_DEINIT_ARG, \
.slot = HSPI_HOST, \
.max_freq_khz = SDMMC_FREQ_DEFAULT, \
.io_voltage = 3.3f, \
.init = &sdspi_host_init, \
.set_bus_width = NULL, \
.get_bus_width = NULL, \
.set_bus_ddr_mode = NULL, \
.set_card_clk = &sdspi_host_set_card_clk, \
.do_transaction = &sdspi_host_do_transaction, \
.deinit_p = &sdspi_host_remove_device, \
.io_int_enable = &sdspi_host_io_int_enable, \
.io_int_wait = &sdspi_host_io_int_wait, \
.command_timeout_ms = 0, \
}
/**
* Extra configuration for SD SPI device.
*/
typedef struct {
spi_host_device_t host_id; ///< SPI host to use, SPIx_HOST (see spi_types.h).
gpio_num_t gpio_cs; ///< GPIO number of CS signal
gpio_num_t gpio_cd; ///< GPIO number of card detect signal
gpio_num_t gpio_wp; ///< GPIO number of write protect signal
gpio_num_t gpio_int; ///< GPIO number of interrupt line (input) for SDIO card.
} sdspi_device_config_t;
#define SDSPI_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used
#define SDSPI_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used
#define SDSPI_SLOT_NO_INT GPIO_NUM_NC ///< indicates that interrupt line is not used
/**
* Macro defining default configuration of SD SPI device.
*/
#define SDSPI_DEVICE_CONFIG_DEFAULT() {\
.host_id = HSPI_HOST, \
.gpio_cs = GPIO_NUM_13, \
.gpio_cd = SDSPI_SLOT_NO_CD, \
.gpio_wp = SDSPI_SLOT_NO_WP, \
.gpio_int = GPIO_NUM_NC, \
}
/**
* @brief Initialize SD SPI driver
*
* @note This function is not thread safe
*
* @return
* - ESP_OK on success
* - other error codes may be returned in future versions
*/
esp_err_t sdspi_host_init(void);
/**
* @brief Attach and initialize an SD SPI device on the specific SPI bus
*
* @note This function is not thread safe
*
* @note Initialize the SPI bus by `spi_bus_initialize()` before calling this function.
*
* @note The SDIO over sdspi needs an extra interrupt line. Call ``gpio_install_isr_service()`` before this function.
*
* @param dev_config pointer to device configuration structure
* @param out_handle Output of the handle to the sdspi device.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if sdspi_host_init_device has invalid arguments
* - ESP_ERR_NO_MEM if memory can not be allocated
* - other errors from the underlying spi_master and gpio drivers
*/
esp_err_t sdspi_host_init_device(const sdspi_device_config_t* dev_config, sdspi_dev_handle_t* out_handle);
/**
* @brief Remove an SD SPI device
*
* @param handle Handle of the SD SPI device
* @return Always ESP_OK
*/
esp_err_t sdspi_host_remove_device(sdspi_dev_handle_t handle);
/**
* @brief Send command to the card and get response
*
* This function returns when command is sent and response is received,
* or data is transferred, or timeout occurs.
*
* @note This function is not thread safe w.r.t. init/deinit functions,
* and bus width/clock speed configuration functions. Multiple tasks
* can call sdspi_host_do_transaction as long as other sdspi_host_*
* functions are not called.
*
* @param handle Handle of the sdspi device
* @param cmdinfo pointer to structure describing command and data to transfer
* @return
* - ESP_OK on success
* - ESP_ERR_TIMEOUT if response or data transfer has timed out
* - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
* - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
*/
esp_err_t sdspi_host_do_transaction(sdspi_dev_handle_t handle, sdmmc_command_t *cmdinfo);
/**
* @brief Set card clock frequency
*
* Currently only integer fractions of 40MHz clock can be used.
* For High Speed cards, 40MHz can be used.
* For Default Speed cards, 20MHz can be used.
*
* @note This function is not thread safe
*
* @param host Handle of the sdspi device
* @param freq_khz card clock frequency, in kHz
* @return
* - ESP_OK on success
* - other error codes may be returned in the future
*/
esp_err_t sdspi_host_set_card_clk(sdspi_dev_handle_t host, uint32_t freq_khz);
/**
* @brief Release resources allocated using sdspi_host_init
*
* @note This function is not thread safe
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if sdspi_host_init function has not been called
*/
esp_err_t sdspi_host_deinit(void);
/**
* @brief Enable SDIO interrupt.
*
* @param handle Handle of the sdspi device
*
* @return
* - ESP_OK on success
*/
esp_err_t sdspi_host_io_int_enable(sdspi_dev_handle_t handle);
/**
* @brief Wait for SDIO interrupt until timeout.
*
* @param handle Handle of the sdspi device
* @param timeout_ticks Ticks to wait before timeout.
*
* @return
* - ESP_OK on success
*/
esp_err_t sdspi_host_io_int_wait(sdspi_dev_handle_t handle, TickType_t timeout_ticks);
/*******************************************************************************
* Deprecated APIs
******************************************************************************/
/**
* Extra configuration for SPI host.
*
* @deprecated Use `sdspi_device_config_t` and corresponding `sdspi_host_init_device()` instead.
*/
typedef struct {
gpio_num_t gpio_cs; ///< GPIO number of CS signal
gpio_num_t gpio_cd; ///< GPIO number of card detect signal
gpio_num_t gpio_wp; ///< GPIO number of write protect signal
gpio_num_t gpio_int; ///< GPIO number of interrupt line (input) for SDIO card.
gpio_num_t gpio_miso; ///< GPIO number of MISO signal.
gpio_num_t gpio_mosi; ///< GPIO number of MOSI signal.
gpio_num_t gpio_sck; ///< GPIO number of SCK signal.
int dma_channel; ///< DMA channel to be used by SPI driver (1 or 2).
} sdspi_slot_config_t;
/**
* Macro defining default configuration of SPI host
*/
#define SDSPI_SLOT_CONFIG_DEFAULT() {\
.gpio_cs = GPIO_NUM_13, \
.gpio_cd = SDSPI_SLOT_NO_CD, \
.gpio_wp = SDSPI_SLOT_NO_WP, \
.gpio_int = GPIO_NUM_NC, \
.gpio_miso = GPIO_NUM_2, \
.gpio_mosi = GPIO_NUM_15, \
.gpio_sck = GPIO_NUM_14, \
.dma_channel = 1, \
}
/**
* @brief Initialize SD SPI driver for the specific SPI controller
*
* @note This function is not thread safe
*
* @note The SDIO over sdspi needs an extra interrupt line. Call ``gpio_install_isr_service()`` before this function.
*
* @param slot SPI controller to use (HSPI_HOST or VSPI_HOST)
* @param slot_config pointer to slot configuration structure
* @deprecated Use `sdspi_host_init_device` instead.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if sdspi_init_slot has invalid arguments
* - ESP_ERR_NO_MEM if memory can not be allocated
* - other errors from the underlying spi_master and gpio drivers
*/
esp_err_t sdspi_host_init_slot(int slot, const sdspi_slot_config_t* slot_config);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,86 @@
// 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_types.h>
#include "soc/soc_caps.h"
#include "soc/sigmadelta_periph.h"
#include "driver/gpio.h"
#include "hal/sigmadelta_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configure Sigma-delta channel
*
* @param config Pointer of Sigma-delta channel configuration struct
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE sigmadelta driver already initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t sigmadelta_config(const sigmadelta_config_t *config);
/**
* @brief Set Sigma-delta channel duty.
*
* This function is used to set Sigma-delta channel duty,
* If you add a capacitor between the output pin and ground,
* the average output voltage will be Vdc = VDDIO / 256 * duty + VDDIO/2,
* where VDDIO is the power supply voltage.
*
* @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.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE sigmadelta driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t sigmadelta_set_duty(sigmadelta_channel_t channel, int8_t duty);
/**
* @brief Set Sigma-delta channel's clock pre-scale value.
* The source clock is APP_CLK, 80MHz. The clock frequency of the sigma-delta channel is APP_CLK / pre_scale
*
* @param channel Sigma-delta channel number
* @param prescale The divider of source clock, ranges from 0 to 255
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE sigmadelta driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t sigmadelta_set_prescale(sigmadelta_channel_t channel, uint8_t prescale);
/**
* @brief Set Sigma-delta signal output pin
*
* @param channel Sigma-delta channel number
* @param gpio_num GPIO number of output pin.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_STATE sigmadelta driver has not been initialized
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t sigmadelta_set_pin(sigmadelta_channel_t channel, gpio_num_t gpio_num);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,162 @@
// 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 <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "soc/lldesc.h"
#include "soc/spi_periph.h"
#include "hal/spi_types.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C"
{
#endif
//Maximum amount of bytes that can be put in one DMA descriptor
#define SPI_MAX_DMA_LEN (4096-4)
/**
* Transform unsigned integer of length <= 32 bits to the format which can be
* sent by the SPI driver directly.
*
* E.g. to send 9 bits of data, you can:
*
* uint16_t data = SPI_SWAP_DATA_TX(0x145, 9);
*
* Then points tx_buffer to ``&data``.
*
* @param DATA Data to be sent, can be uint8_t, uint16_t or uint32_t.
* @param LEN Length of data to be sent, since the SPI peripheral sends from
* the MSB, this helps to shift the data to the MSB.
*/
#define SPI_SWAP_DATA_TX(DATA, LEN) __builtin_bswap32((uint32_t)(DATA)<<(32-(LEN)))
/**
* Transform received data of length <= 32 bits to the format of an unsigned integer.
*
* E.g. to transform the data of 15 bits placed in a 4-byte array to integer:
*
* uint16_t data = SPI_SWAP_DATA_RX(*(uint32_t*)t->rx_data, 15);
*
* @param DATA Data to be rearranged, can be uint8_t, uint16_t or uint32_t.
* @param LEN Length of data received, since the SPI peripheral writes from
* the MSB, this helps to shift the data to the LSB.
*/
#define SPI_SWAP_DATA_RX(DATA, LEN) (__builtin_bswap32(DATA)>>(32-(LEN)))
#define SPICOMMON_BUSFLAG_SLAVE 0 ///< Initialize I/O in slave mode
#define SPICOMMON_BUSFLAG_MASTER (1<<0) ///< Initialize I/O in master mode
#define SPICOMMON_BUSFLAG_IOMUX_PINS (1<<1) ///< Check using iomux pins. Or indicates the pins are configured through the IO mux rather than GPIO matrix.
#define SPICOMMON_BUSFLAG_GPIO_PINS (1<<2) ///< Force the signals to be routed through GPIO matrix. Or indicates the pins are routed through the GPIO matrix.
#define SPICOMMON_BUSFLAG_SCLK (1<<3) ///< Check existing of SCLK pin. Or indicates CLK line initialized.
#define SPICOMMON_BUSFLAG_MISO (1<<4) ///< Check existing of MISO pin. Or indicates MISO line initialized.
#define SPICOMMON_BUSFLAG_MOSI (1<<5) ///< Check existing of MOSI pin. Or indicates MOSI line initialized.
#define SPICOMMON_BUSFLAG_DUAL (1<<6) ///< Check MOSI and MISO pins can output. Or indicates bus able to work under DIO mode.
#define SPICOMMON_BUSFLAG_WPHD (1<<7) ///< Check existing of WP and HD pins. Or indicates WP & HD pins initialized.
#define SPICOMMON_BUSFLAG_QUAD (SPICOMMON_BUSFLAG_DUAL|SPICOMMON_BUSFLAG_WPHD) ///< Check existing of MOSI/MISO/WP/HD pins as output. Or indicates bus able to work under QIO mode.
#define SPICOMMON_BUSFLAG_NATIVE_PINS SPICOMMON_BUSFLAG_IOMUX_PINS
/**
* @brief SPI DMA channels
*/
typedef enum {
SPI_DMA_DISABLED = 0, ///< Do not enable DMA for SPI
#if CONFIG_IDF_TARGET_ESP32
SPI_DMA_CH1 = 1, ///< Enable DMA, select DMA Channel 1
SPI_DMA_CH2 = 2, ///< Enable DMA, select DMA Channel 2
#endif
SPI_DMA_CH_AUTO = 3, ///< Enable DMA, channel is automatically selected by driver
} spi_common_dma_t;
#if __cplusplus
/* Needed for C++ backwards compatibility with earlier ESP-IDF where this argument is a bare 'int'. Can be removed in ESP-IDF 5 */
typedef int spi_dma_chan_t;
#else
typedef spi_common_dma_t spi_dma_chan_t;
#endif
/**
* @brief This is a configuration structure for a SPI bus.
*
* You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
* the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
*
* @note Be advised that the slave driver does not use the quadwp/quadhd lines and fields in spi_bus_config_t refering to these lines will be ignored and can thus safely be left uninitialized.
*/
typedef struct {
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
uint32_t flags; ///< Abilities of bus to be checked by the driver. Or-ed value of ``SPICOMMON_BUSFLAG_*`` flags.
int intr_flags; /**< Interrupt flag for the bus to set the priority, and IRAM attribute, see
* ``esp_intr_alloc.h``. Note that the EDGE, INTRDISABLED attribute are ignored
* by the driver. Note that if ESP_INTR_FLAG_IRAM is set, ALL the callbacks of
* the driver, and their callee functions, should be put in the IRAM.
*/
} spi_bus_config_t;
/**
* @brief Initialize a SPI bus
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host_id SPI peripheral that controls this bus
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param dma_chan - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.
* - Selecting SPI_DMA_DISABLED limits the size of transactions.
* - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.
* - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan);
/**
* @brief Free a SPI bus
*
* @warning In order for this to succeed, all devices have to be removed first.
*
* @param host_id SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_bus_free(spi_host_device_t host_id);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,786 @@
// 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.
// Internal header, don't use it in the user code
#pragma once
#include <esp_intr_alloc.h>
#include "driver/spi_common.h"
#include "freertos/FreeRTOS.h"
#include "hal/spi_types.h"
#include "esp_pm.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef CONFIG_SPI_MASTER_ISR_IN_IRAM
#define SPI_MASTER_ISR_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ISR_ATTR
#endif
#ifdef CONFIG_SPI_MASTER_IN_IRAM
#define SPI_MASTER_ATTR IRAM_ATTR
#else
#define SPI_MASTER_ATTR
#endif
#define BUS_LOCK_DEBUG 0
#if BUS_LOCK_DEBUG
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x) assert(x)
#else
#define BUS_LOCK_DEBUG_EXECUTE_CHECK(x)
#endif
struct spi_bus_lock_t;
struct spi_bus_lock_dev_t;
/// Handle to the lock of an SPI bus
typedef struct spi_bus_lock_t* spi_bus_lock_handle_t;
/// Handle to lock of one of the device on an SPI bus
typedef struct spi_bus_lock_dev_t* spi_bus_lock_dev_handle_t;
/// Background operation control function
typedef void (*bg_ctrl_func_t)(void*);
/// Attributes of an SPI bus
typedef struct {
spi_bus_config_t bus_cfg; ///< Config used to initialize the bus
uint32_t flags; ///< Flags (attributes) of the bus
int max_transfer_sz; ///< Maximum length of bytes available to send
bool dma_enabled; ///< To enable DMA or not
int tx_dma_chan; ///< TX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same
int rx_dma_chan; ///< RX DMA channel, on ESP32 and ESP32S2, tx_dma_chan and rx_dma_chan are same
int dma_desc_num; ///< DMA descriptor number of dmadesc_tx or dmadesc_rx.
lldesc_t *dmadesc_tx; ///< DMA descriptor array for TX
lldesc_t *dmadesc_rx; ///< DMA descriptor array for RX
spi_bus_lock_handle_t lock;
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t pm_lock; ///< Power management lock
#endif
} spi_bus_attr_t;
/// Destructor called when a bus is deinitialized.
typedef esp_err_t (*spi_destroy_func_t)(void*);
/**
* @brief Try to claim a SPI peripheral
*
* Call this if your driver wants to manage a SPI peripheral.
*
* @param host Peripheral to claim
* @param source The caller indentification string.
*
* @note This public API is deprecated.
*
* @return True if peripheral is claimed successfully; false if peripheral already is claimed.
*/
bool spicommon_periph_claim(spi_host_device_t host, const char* source);
/**
* @brief Check whether the spi periph is in use.
*
* @param host Peripheral to check.
*
* @note This public API is deprecated.
*
* @return True if in use, otherwise false.
*/
bool spicommon_periph_in_use(spi_host_device_t host);
/**
* @brief Return the SPI peripheral so another driver can claim it.
*
* @param host Peripheral to return
*
* @note This public API is deprecated.
*
* @return True if peripheral is returned successfully; false if peripheral was free to claim already.
*/
bool spicommon_periph_free(spi_host_device_t host);
/**
* @brief Alloc DMA for SPI Slave
*
* @param host_id SPI host ID
* @param dma_chan DMA channel to be used
* @param[out] out_actual_tx_dma_chan Actual TX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before)
* @param[out] out_actual_rx_dma_chan Actual RX DMA channel (if you choose to assign a specific DMA channel, this will be the channel you assigned before)
*
* @return
* - ESP_OK: On success
* - ESP_ERR_NO_MEM: No enough memory
* - ESP_ERR_NOT_FOUND: There is no available DMA channel
*/
esp_err_t spicommon_slave_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan);
/**
* @brief Free DMA for SPI Slave
*
* @param host_id SPI host ID
*
* @return
* - ESP_OK: On success
*/
esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id);
/**
* @brief Connect a SPI peripheral to GPIO pins
*
* This routine is used to connect a SPI peripheral to the IO-pads and DMA channel given in
* the arguments. Depending on the IO-pads requested, the routing is done either using the
* IO_mux or using the GPIO matrix.
*
* @note This public API is deprecated. Please call ``spi_bus_initialize`` for master
* bus initialization and ``spi_slave_initialize`` for slave initialization.
*
* @param host SPI peripheral to be routed
* @param bus_config Pointer to a spi_bus_config struct detailing the GPIO pins
* @param flags Combination of SPICOMMON_BUSFLAG_* flags, set to ensure the pins set are capable with some functions:
* - ``SPICOMMON_BUSFLAG_MASTER``: Initialize I/O in master mode
* - ``SPICOMMON_BUSFLAG_SLAVE``: Initialize I/O in slave mode
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: Pins set should match the iomux pins of the controller.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``:
* Make sure SCLK/MISO/MOSI is/are set to a valid GPIO. Also check output capability according to the mode.
* - ``SPICOMMON_BUSFLAG_DUAL``: Make sure both MISO and MOSI are output capable so that DIO mode is capable.
* - ``SPICOMMON_BUSFLAG_WPHD`` Make sure WP and HD are set to valid output GPIOs.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @param[out] flags_o A SPICOMMON_BUSFLAG_* flag combination of bus abilities will be written to this address.
* Leave to NULL if not needed.
* - ``SPICOMMON_BUSFLAG_IOMUX_PINS``: The bus is connected to iomux pins.
* - ``SPICOMMON_BUSFLAG_SCLK``, ``SPICOMMON_BUSFLAG_MISO``, ``SPICOMMON_BUSFLAG_MOSI``: The bus has
* CLK/MISO/MOSI connected.
* - ``SPICOMMON_BUSFLAG_DUAL``: The bus is capable with DIO mode.
* - ``SPICOMMON_BUSFLAG_WPHD`` The bus has WP and HD connected.
* - ``SPICOMMON_BUSFLAG_QUAD``: Combination of ``SPICOMMON_BUSFLAG_DUAL`` and ``SPICOMMON_BUSFLAG_WPHD``.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t *flags_o);
/**
* @brief Free the IO used by a SPI peripheral
*
* @note This public API is deprecated. Please call ``spi_bus_free`` for master
* bus deinitialization and ``spi_slave_free`` for slave deinitialization.
*
* @param bus_cfg Bus config struct which defines which pins to be used.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg);
/**
* @brief Initialize a Chip Select pin for a specific SPI peripheral
*
* @note This public API is deprecated. Please call corresponding device initialization
* functions.
*
* @param host SPI peripheral
* @param cs_io_num GPIO pin to route
* @param cs_num CS id to route
* @param force_gpio_matrix If true, CS will always be routed through the GPIO matrix. If false,
* if the GPIO number allows it, the routing will happen through the IO_mux.
*/
void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix);
/**
* @brief Free a chip select line
*
* @param cs_gpio_num CS gpio num to free
*
* @note This public API is deprecated.
*/
void spicommon_cs_free_io(int cs_gpio_num);
/**
* @brief Check whether all pins used by a host are through IOMUX.
*
* @param host SPI peripheral
*
* @note This public API is deprecated.
*
* @return false if any pins are through the GPIO matrix, otherwise true.
*/
bool spicommon_bus_using_iomux(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI host
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqsource_for_host(spi_host_device_t host);
/**
* @brief Get the IRQ source for a specific SPI DMA
*
* @param host The SPI host
*
* @note This public API is deprecated.
*
* @return The hosts IRQ source
*/
int spicommon_irqdma_source_for_host(spi_host_device_t host);
/**
* Callback, to be called when a DMA engine reset is completed
*/
typedef void(*dmaworkaround_cb_t)(void *arg);
/**
* @brief Request a reset for a certain DMA channel
*
* @note In some (well-defined) cases in the ESP32 (at least rev v.0 and v.1), a SPI DMA channel will get confused. This can be remedied
* by resetting the SPI DMA hardware in case this happens. Unfortunately, the reset knob used for thsi will reset _both_ DMA channels, and
* as such can only done safely when both DMA channels are idle. These functions coordinate this.
*
* Essentially, when a reset is needed, a driver can request this using spicommon_dmaworkaround_req_reset. This is supposed to be called
* with an user-supplied function as an argument. If both DMA channels are idle, this call will reset the DMA subsystem and return true.
* If the other DMA channel is still busy, it will return false; as soon as the other DMA channel is done, however, it will reset the
* DMA subsystem and call the callback. The callback is then supposed to be used to continue the SPI drivers activity.
*
* @param dmachan DMA channel associated with the SPI host that needs a reset
* @param cb Callback to call in case DMA channel cannot be reset immediately
* @param arg Argument to the callback
*
* @note This public API is deprecated.
*
* @return True when a DMA reset could be executed immediately. False when it could not; in this
* case the callback will be called with the specified argument when the logic can execute
* a reset, after that reset.
*/
bool spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg);
/**
* @brief Check if a DMA reset is requested but has not completed yet
*
* @note This public API is deprecated.
*
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
*/
bool spicommon_dmaworkaround_reset_in_progress(void);
/**
* @brief Mark a DMA channel as idle.
*
* A call to this function tells the workaround logic that this channel will
* not be affected by a global SPI DMA reset.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_idle(int dmachan);
/**
* @brief Mark a DMA channel as active.
*
* A call to this function tells the workaround logic that this channel will
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
*
* @note This public API is deprecated.
*/
void spicommon_dmaworkaround_transfer_active(int dmachan);
/*******************************************************************************
* Bus attributes
******************************************************************************/
/**
* @brief Set bus lock for the main bus, called by startup code.
*
* @param lock The lock to be used by the main SPI bus.
*/
void spi_bus_main_set_lock(spi_bus_lock_handle_t lock);
/**
* @brief Get the attributes of a specified SPI bus.
*
* @param host_id The specified host to get attribute
* @return (Const) Pointer to the attributes
*/
const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id);
/**
* @brief Register a function to a initialized bus to make it called when deinitializing the bus.
*
* @param host_id The SPI bus to register the destructor.
* @param f Destructor to register
* @param arg The argument to call the destructor
* @return Always ESP_OK.
*/
esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
spi_destroy_func_t f, void *arg);
/*******************************************************************************
* SPI Bus Lock for arbitration among SPI master (intr, polling) trans, SPI flash operations and
* flash/psram cache access.
*
* NON-PUBLIC API. Don't use it directly in applications.
*
* There is the main lock corresponding to an SPI bus, of which several devices (holding child
* locks) attaching to it. Each of the device is STRONGLY RECOMMENDED to be used in only one task
* to avoid concurrency issues.
*
* Terms:
* - BG operations (BackGround operations) means some transaction that will not immediately /
* explicitly be sent in the task. It can be some cache access, or interrupt transactions.
*
* - Operation: usage of the bus, for example, do SPI transactions.
*
* - Acquiring processor: the task or the ISR that is allowed to use the bus. No operations will be
* performed if there is no acquiring processor. A processor becomes the acquiring processor if
* it ask for that when no acquiring processor exist, otherwise it has to wait for the acquiring
* processor to handle over the role to it. The acquiring processor will and will only assign one
* acquiring processor in the waiting list (if not empty) when it finishes its operation.
*
* - Acquiring device: the only device allowed to use the bus. Operations can be performed in
* either the BG or the task. When there's no acquiring device, only the ISR is allowed to be the
* acquiring processor and perform operations on the bus.
*
* When a device wants to perform operations, it either:
* 1. Acquire the bus, and operate in the task (e.g. polling transactions of SPI master, and SPI flash
* operations)
*
* 2. Request a BG operation. And the ISR will be enabled at proper time.
*
* For example if a task wants to send an interrupt transaction, it prepares the data in the task,
* call `spi_bus_lock_bg_request`, and handle sending in the ISR.
*
* 3. When a device has already acquired the bus, BG operations are also allowed. After the
* `spi_bus_lock_bg_request` is called, call `spi_bus_lock_wait_bg_done` before operations in task
* again to wait until BG operations are done.
*
* Any device may try to invoke the ISR (by `spi_bus_lock_bg_request`). The ISR will be invoked and
* become the acquiring processor immediately when the bus is not acquired by other processors. Any
* device may also try to acquire the bus (by `spi_bus_lock_acquire_start`). The device will become
* the acquiring processor immediately when the bus is not acquired and there is no request active.
*
* The acquiring processor must be aware of its acquiring role, and properly transfer the acquiring
* processor to other tasks or ISR when they have nothing else to do. Before picking a new
* acquiring processor, a new acquiring device must be picked first, if there are other devices,
* asking to be acquiring device. After that, the new acquiring processor is picked by the sequence
* below:
*
* 1. If there is an acquiring device:
* 1.1 The ISR, if acquiring device has active BG requests
* 1.2 The task of the device, if no active BG request for the device
* 2. The ISR, if there's no acquiring device, but any BG request is active
* 3. No one becomes the acquiring processor
*
* The API also helps on the arbitration of SPI cs lines. The bus is initialized with a cs_num
* argument. When attaching devices onto the bus with `spi_bus_lock_register_dev`, it will allocate
* devices with different device ID according to the flags given. If the ID is smaller than the
* cs_num given when bus is initialized, error will be returned.
*
* Usage:
* * Initialization:
* 1. Call `spi_bus_init_lock` to register a lock for a bus.
* 2. Call `spi_bus_lock_set_bg_control` to prepare BG enable/disable functions for
* the lock.
* 3. Call `spi_bus_lock_register_dev` for each devices that may make use of the
* bus, properly store the returned handle, representing those devices.
*
* * Acquiring:
* 1. Call `spi_bus_lock_acquire_start` when a device wants to use the bus
* 2. Call `spi_bus_lock_touch` to mark the bus as touched by this device. Also check if the bus
* has been touched by other devices.
* 3. (optional) Do something on the bus...
* 4. (optional) Call `spi_bus_lock_bg_request` to inform and invoke the BG. See ISR below about
* ISR operations.
* 5. (optional) If `spi_bus_lock_bg_request` is done, you have to call `spi_bus_lock_wait_bg_done`
* before touching the bus again, or do the following steps.
* 6. Call `spi_bus_lock_acquire_end` to release the bus to other devices.
*
* * ISR:
* 1. Call `spi_bus_lock_bg_entry` when entering the ISR, run or skip the closure for the previous
* operation according to the return value.
* 2. Call `spi_bus_lock_get_acquiring_dev` to get the acquiring device. If there is no acquiring
* device, call `spi_bus_lock_bg_check_dev_acq` to check and update a new acquiring device.
* 3. Call `spi_bus_lock_bg_check_dev_req` to check for request of the desired device. If the
* desired device is not requested, go to step 5.
* 4. Check, start operation for the desired device and go to step 6; otherwise if no operations
* can be performed, call `spi_bus_lock_bg_clear_req` to clear the request for this device. If
* `spi_bus_lock_bg_clear_req` is called and there is no BG requests active, goto step 6.
* 5. (optional) If the device is the acquiring device, go to step 6, otherwise
* find another desired device, and go back to step 3.
* 6. Call `spi_bus_lock_bg_exit` to try quitting the ISR. If failed, go back to step 2 to look for
* a new request again. Otherwise, quit the ISR.
*
* * Deinitialization (optional):
* 1. Call `spi_bus_lock_unregister_dev` for each device when they are no longer needed.
* 2. Call `spi_bus_deinit_lock` to release the resources occupied by the lock.
*
* Some technical details:
*
* The child-lock of each device will have its own Binary Semaphore, which allows the task serving
* this device (task A) being blocked when it fail to become the acquiring processor while it's
* calling `spi_bus_lock_acquire_start` or `spi_bus_lock_wait_bg_done`. If it is blocked, there
* must be an acquiring processor (either the ISR or another task (task B)), is doing transaction
* on the bus. After that, task A will get unblocked and become the acquiring processor when the
* ISR call `spi_bus_lock_bg_resume_acquired_dev`, or task B call `spi_bus_lock_acquire_end`.
*
* When the device wants to send ISR transaction, it should call `spi_bus_lock_bg_request` after
* the data is prepared. This function sets a request bit in the critical resource. The ISR will be
* invoked and become the new acquiring processor, when:
*
* 1. A task calls `spi_bus_lock_bg_request` while there is no acquiring processor;
* 2. A tasks calls `spi_bus_lock_bg_request` while the task is the acquiring processor. Then the
* acquiring processor is handled over to the ISR;
* 3. A tasks who is the acquiring processor release the bus by calling `spi_bus_lock_acquire_end`,
* and the ISR happens to be the next acquiring processor.
*
* The ISR will check (by `spi_bus_lock_bg_check_dev_req`) and clear a request bit (by
* `spi_bus_lock_bg_clear_req`) after it confirm that all the requests of the corresponding device
* are served. The request bit supports being written to recursively, which means, the task don't
* need to wait for `spi_bus_lock_bg_clear_req` before call another `spi_bus_lock_bg_request`. The
* API will handle the concurrency conflicts properly.
*
* The `spi_bus_lock_bg_exit` (together with `spi_bus_lock_bg_entry` called before)` is responsible
* to ensure ONE and ONLY ONE of the following will happen when the ISR try to give up its
* acquiring processor rule:
*
* 1. ISR quit, no any task unblocked while the interrupt disabled, and none of the BG bits is
* active.
* 2. ISR quit, there is an acquiring device, and the acquiring processor is passed to the task
* serving the acquiring device by unblocking the task.
* 3. The ISR failed to quit and have to try again.
******************************************************************************/
#define DEV_NUM_MAX 6 ///< Number of devices supported by this lock
/// Lock configuration struct
typedef struct {
int host_id; ///< SPI host id
int cs_num; ///< Physical cs numbers of the host
} spi_bus_lock_config_t;
/// Child-lock configuration struct
typedef struct {
uint32_t flags; ///< flags for the lock, OR-ed of `SPI_BUS_LOCK_DEV_*` flags.
#define SPI_BUS_LOCK_DEV_FLAG_CS_REQUIRED BIT(0) ///< The device needs a physical CS pin.
} spi_bus_lock_dev_config_t;
/************* Common *********************/
/**
* Initialize a lock for an SPI bus.
*
* @param out_lock Output of the handle to the lock
* @return
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_init_lock(spi_bus_lock_handle_t *out_lock, const spi_bus_lock_config_t *config);
/**
* Free the resources used by an SPI bus lock.
*
* @note All attached devices should have been unregistered before calling this
* funciton.
*
* @param lock Handle to the lock to free.
*/
void spi_bus_deinit_lock(spi_bus_lock_handle_t lock);
/**
* @brief Get the corresponding lock according to bus id.
*
* @param host_id The bus id to get the lock
* @return The lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id);
/**
* @brief Configure how the SPI bus lock enable the background operation.
*
* @note The lock will not try to stop the background operations, but wait for
* The background operations finished indicated by `spi_bus_lock_bg_resume_acquired_dev`.
*
* @param lock Handle to the lock to set
* @param bg_enable The enabling function
* @param bg_disable The disabling function, set to NULL if not required
* @param arg Argument to pass to the enabling/disabling function.
*/
void spi_bus_lock_set_bg_control(spi_bus_lock_handle_t lock, bg_ctrl_func_t bg_enable,
bg_ctrl_func_t bg_disable, void *arg);
/**
* Attach a device onto an SPI bus lock. The returning handle is used to perform
* following requests for the attached device.
*
* @param lock SPI bus lock to attach
* @param out_dev_handle Output handle corresponding to the device
* @param flags requirement of the device, bitwise OR of SPI_BUS_LOCK_FLAG_* flags
*
* @return
* - ESP_ERR_NOT_SUPPORTED: if there's no hardware resources for new devices.
* - ESP_ERR_NO_MEM: if memory exhausted
* - ESP_OK: if success
*/
esp_err_t spi_bus_lock_register_dev(spi_bus_lock_handle_t lock,
spi_bus_lock_dev_config_t *config,
spi_bus_lock_dev_handle_t *out_dev_handle);
/**
* Detach a device from its bus and free the resources used
*
* @param dev_handle Handle to the device.
*/
void spi_bus_lock_unregister_dev(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the parent bus lock of the device
*
* @param dev_handle Handle to the device to get bus lock
* @return The bus lock handle
*/
spi_bus_lock_handle_t spi_bus_lock_get_parent(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief Get the device ID of a lock.
*
* The callers should allocate CS pins according to this ID.
*
* @param dev_handle Handle to the device to get ID
* @return ID of the device
*/
int spi_bus_lock_get_dev_id(spi_bus_lock_dev_handle_t dev_handle);
/**
* @brief The device request to touch bus registers. Can only be called by the acquiring processor.
*
* Also check if the registers has been touched by other devices.
*
* @param dev_handle Handle to the device to operate the registers
* @return true if there has been other devices touching SPI registers.
* The caller may need to do a full-configuration. Otherwise return
* false.
*/
bool spi_bus_lock_touch(spi_bus_lock_dev_handle_t dev_handle);
/************* Acquiring service *********************/
/**
* Acquiring the SPI bus for exclusive use. Will also wait for the BG to finish all requests of
* this device before it returns.
*
* After successfully return, the caller becomes the acquiring processor.
*
* @note For the main flash bus, `bg_disable` will be called to disable the cache.
*
* @param dev_handle Handle to the device request for acquiring.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: timeout is not portMAX_DELAY
*/
esp_err_t spi_bus_lock_acquire_start(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Release the bus acquired. Will pass the acquiring processor to other blocked
* processors (tasks or ISR), and cause them to be unblocked or invoked.
*
* The acquiring device may also become NULL if no device is asking for acquiring.
* In this case, the BG may be invoked if there is any BG requests.
*
* If the new acquiring device has BG requests, the BG will be invoked before the
* task is resumed later after the BG finishes all requests of the new acquiring
* device. Otherwise the task of the new acquiring device will be resumed immediately.
*
* @param dev_handle Handle to the device releasing the bus.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: the device hasn't acquired the lock yet
*/
esp_err_t spi_bus_lock_acquire_end(spi_bus_lock_dev_handle_t dev_handle);
/**
* Get the device acquiring the bus.
*
* @note Return value is not stable as the acquiring processor may change
* when this function is called.
*
* @param lock Lock of SPI bus to get the acquiring device.
* @return The argument corresponding to the acquiring device, see
* `spi_bus_lock_register_dev`.
*/
spi_bus_lock_dev_handle_t spi_bus_lock_get_acquiring_dev(spi_bus_lock_handle_t lock);
/************* BG (Background, for ISR or cache) service *********************/
/**
* Call by a device to request a BG operation.
*
* Depending on the bus lock state, the BG operations may be resumed by this
* call, or pending until BG operations allowed.
*
* Cleared by `spi_bus_lock_bg_clear_req` in the BG.
*
* @param dev_handle The device requesting BG operations.
* @return always ESP_OK
*/
esp_err_t spi_bus_lock_bg_request(spi_bus_lock_dev_handle_t dev_handle);
/**
* Wait until the ISR has finished all the BG operations for the acquiring device.
* If any `spi_bus_lock_bg_request` for this device has been called after
* `spi_bus_lock_acquire_start`, this function must be called before any operation
* in the task.
*
* @note Can only be called when bus acquired by this device.
*
* @param dev_handle Handle to the device acquiring the bus.
* @param wait Time to wait until timeout or succeed, must be `portMAX_DELAY` for now.
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: The device is not the acquiring bus.
* - ESP_ERR_INVALID_ARG: Timeout is not portMAX_DELAY.
*/
esp_err_t spi_bus_lock_wait_bg_done(spi_bus_lock_dev_handle_t dev_handle, TickType_t wait);
/**
* Handle interrupt and closure of last operation. Should be called at the beginning of the ISR,
* when the ISR is acting as the acquiring processor.
*
* @param lock The SPI bus lock
*
* @return false if the ISR has already touched the HW, should run closure of the
* last operation first; otherwise true if the ISR just start operating
* on the HW, closure should be skipped.
*/
bool spi_bus_lock_bg_entry(spi_bus_lock_handle_t lock);
/**
* Handle the scheduling of other acquiring devices, and control of HW operation
* status.
*
* If no BG request is found, call with `wip=false`. This function will return false,
* indicating there is incoming BG requests for the current acquiring device (or
* for all devices if there is no acquiring device) and the ISR needs retry.
* Otherwise may schedule a new acquiring processor (unblock the task) if there
* is, and return true.
*
* Otherwise if a BG request is started in this ISR, call with `wip=true` and the
* function will enable the interrupt to make the ISR be called again when the
* request is done.
*
* This function is safe and should still be called when the ISR just lost its acquiring processor
* role, but hasn't quit.
*
* @note This function will not change acquiring device. The ISR call
* `spi_bus_lock_bg_update_acquiring` to check for new acquiring device,
* when acquiring devices need to be served before other devices.
*
* @param lock The SPI bus lock.
* @param wip Whether an operation is being executed when quitting the ISR.
* @param do_yield[out] Not touched when no yielding required, otherwise set
* to pdTRUE.
* @return false if retry is required, indicating that there is pending BG request.
* otherwise true and quit ISR is allowed.
*/
bool spi_bus_lock_bg_exit(spi_bus_lock_handle_t lock, bool wip, BaseType_t* do_yield);
/**
* Check whether there is device asking for the acquiring device, and the desired
* device for the next operation is also recommended.
*
* @note Must be called when the ISR is acting as the acquiring processor, and
* there is no acquiring device.
*
* @param lock The SPI bus lock.
* @param out_dev_lock The recommended device for hte next operation. It's the new
* acquiring device when found, otherwise a device that has active BG request.
*
* @return true if the ISR need to quit (new acquiring device has no active BG
* request, or no active BG requests for all devices when there is no
* acquiring device), otherwise false.
*/
bool spi_bus_lock_bg_check_dev_acq(spi_bus_lock_handle_t lock, spi_bus_lock_dev_handle_t *out_dev_lock);
/**
* Check if the device has BG requests. Must be called when the ISR is acting as
* the acquiring processor.
*
* @note This is not stable, may become true again when a task request for BG
* operation (by `spi_bus_lock_bg_request`).
*
* @param dev_lock The device to check.
* @return true if the device has BG requests, otherwise false.
*/
bool spi_bus_lock_bg_check_dev_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Clear the pending BG operation request of a device after served. Must be
* called when the ISR is acting as the acquiring processor.
*
* @note When the return value is true, the ISR will lost the acquiring processor role. Then
* `spi_bus_lock_bg_exit` must be called and checked before calling all other functions that
* require to be called when the ISR is the acquiring processor again.
*
* @param dev_handle The device whose request is served.
* @return True if no pending requests for the acquiring device, or for all devices
* if there is no acquiring device. Otherwise false. When the return value is
* true, the ISR is no longer the acquiring processor.
*/
bool spi_bus_lock_bg_clear_req(spi_bus_lock_dev_handle_t dev_lock);
/**
* Check if there is any active BG requests.
*
* @param lock The SPI bus lock.
* @return true if any device has active BG requst, otherwise false.
*/
bool spi_bus_lock_bg_req_exist(spi_bus_lock_handle_t lock);
/*******************************************************************************
* Variable and APIs for the OS to initialize the locks for the main chip
******************************************************************************/
/// The lock for the main bus
extern const spi_bus_lock_handle_t g_main_spi_bus_lock;
/**
* @brief Initialize the main SPI bus, called during chip startup.
*
* @return always ESP_OK
*/
esp_err_t spi_bus_lock_init_main_bus(void);
/// The lock for the main flash device
extern const spi_bus_lock_dev_handle_t g_spi_lock_main_flash_dev;
/**
* @brief Initialize the main flash device, called during chip startup.
*
* @return
* - ESP_OK: if success
* - ESP_ERR_NO_MEM: memory exhausted
*/
esp_err_t spi_bus_lock_init_main_dev(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,392 @@
// 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_err.h"
#include "freertos/FreeRTOS.h"
//for spi_bus_initialization funcions. to be back-compatible
#include "driver/spi_common.h"
/** SPI master clock is divided by 80MHz apb clock. Below defines are example frequencies, and are accurate. Be free to specify a random frequency, it will be rounded to closest frequency (to macros below if above 8MHz).
* 8MHz
*/
#define SPI_MASTER_FREQ_8M (APB_CLK_FREQ/10)
#define SPI_MASTER_FREQ_9M (APB_CLK_FREQ/9) ///< 8.89MHz
#define SPI_MASTER_FREQ_10M (APB_CLK_FREQ/8) ///< 10MHz
#define SPI_MASTER_FREQ_11M (APB_CLK_FREQ/7) ///< 11.43MHz
#define SPI_MASTER_FREQ_13M (APB_CLK_FREQ/6) ///< 13.33MHz
#define SPI_MASTER_FREQ_16M (APB_CLK_FREQ/5) ///< 16MHz
#define SPI_MASTER_FREQ_20M (APB_CLK_FREQ/4) ///< 20MHz
#define SPI_MASTER_FREQ_26M (APB_CLK_FREQ/3) ///< 26.67MHz
#define SPI_MASTER_FREQ_40M (APB_CLK_FREQ/2) ///< 40MHz
#define SPI_MASTER_FREQ_80M (APB_CLK_FREQ/1) ///< 80MHz
#ifdef __cplusplus
extern "C"
{
#endif
#define SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
#define SPI_DEVICE_BIT_LSBFIRST (SPI_DEVICE_TXBIT_LSBFIRST|SPI_DEVICE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
#define SPI_DEVICE_3WIRE (1<<2) ///< Use MOSI (=spid) for both sending and receiving data
#define SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative
#define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously
#define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active
/** There are timing issue when reading at high frequency (the frequency is related to whether iomux pins are used, valid time after slave sees the clock).
* - In half-duplex mode, the driver automatically inserts dummy bits before reading phase to fix the timing issue. Set this flag to disable this feature.
* - In full-duplex mode, however, the hardware cannot use dummy bits, so there is no way to prevent data being read from getting corrupted.
* Set this flag to confirm that you're going to work with output only, or read without dummy bits at your own risk.
*/
#define SPI_DEVICE_NO_DUMMY (1<<6)
#define SPI_DEVICE_DDRCLK (1<<7)
typedef struct spi_transaction_t spi_transaction_t;
typedef void(*transaction_cb_t)(spi_transaction_t *trans);
/**
* @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses.
*/
typedef struct {
uint8_t command_bits; ///< Default amount of bits in command phase (0-16), used when ``SPI_TRANS_VARIABLE_CMD`` is not used, otherwise ignored.
uint8_t address_bits; ///< Default amount of bits in address phase (0-64), used when ``SPI_TRANS_VARIABLE_ADDR`` is not used, otherwise ignored.
uint8_t dummy_bits; ///< Amount of dummy bits to insert between address and data phase
uint8_t mode; /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:
- 0: (0, 0)
- 1: (0, 1)
- 2: (1, 0)
- 3: (1, 1)
*/
uint16_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.
uint16_t cs_ena_pretrans; ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.
uint8_t cs_ena_posttrans; ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)
int clock_speed_hz; ///< Clock speed, divisors of 80MHz, in Hz. See ``SPI_MASTER_FREQ_*``.
int input_delay_ns; /**< Maximum data valid time of slave. The time required between SCLK and MISO
valid, including the possible clock delay from slave to master. The driver uses this value to give an extra
delay before the MISO is ready on the line. Leave at 0 unless you know you need a delay. For better timing
performance at high frequency (over 8MHz), it's suggest to have the right value.
*/
int spics_io_num; ///< CS GPIO pin for this device, or -1 if not used
uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_device_queue_trans but not yet finished using spi_device_get_trans_result) at the same time
transaction_cb_t pre_cb; /**< Callback to be called before a transmission is started.
*
* This callback is called within interrupt
* context should be in IRAM for best
* performance, see "Transferring Speed"
* section in the SPI Master documentation for
* full details. If not, the callback may crash
* during flash operation when the driver is
* initialized with ESP_INTR_FLAG_IRAM.
*/
transaction_cb_t post_cb; /**< Callback to be called after a transmission has completed.
*
* This callback is called within interrupt
* context should be in IRAM for best
* performance, see "Transferring Speed"
* section in the SPI Master documentation for
* full details. If not, the callback may crash
* during flash operation when the driver is
* initialized with ESP_INTR_FLAG_IRAM.
*/
} spi_device_interface_config_t;
#define SPI_TRANS_MODE_DIO (1<<0) ///< Transmit/receive data in 2-bit mode
#define SPI_TRANS_MODE_QIO (1<<1) ///< Transmit/receive data in 4-bit mode
#define SPI_TRANS_USE_RXDATA (1<<2) ///< Receive into rx_data member of spi_transaction_t instead into memory at rx_buffer.
#define SPI_TRANS_USE_TXDATA (1<<3) ///< Transmit tx_data member of spi_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this.
#define SPI_TRANS_MODE_DIOQIO_ADDR (1<<4) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO
#define SPI_TRANS_VARIABLE_CMD (1<<5) ///< Use the ``command_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
#define SPI_TRANS_VARIABLE_ADDR (1<<6) ///< Use the ``address_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
#define SPI_TRANS_VARIABLE_DUMMY (1<<7) ///< Use the ``dummy_bits`` in ``spi_transaction_ext_t`` rather than default value in ``spi_device_interface_config_t``.
#define SPI_TRANS_SET_CD (1<<7) ///< Set the CD pin
/**
* This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes.
*/
struct spi_transaction_t {
uint32_t flags; ///< Bitwise OR of SPI_TRANS_* flags
uint16_t cmd; /**< Command data, of which the length is set in the ``command_bits`` of spi_device_interface_config_t.
*
* <b>NOTE: this field, used to be "command" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF 3.0.</b>
*
* Example: write 0x0123 and command_bits=12 to send command 0x12, 0x3_ (in previous version, you may have to write 0x3_12).
*/
uint64_t addr; /**< Address data, of which the length is set in the ``address_bits`` of spi_device_interface_config_t.
*
* <b>NOTE: this field, used to be "address" in ESP-IDF 2.1 and before, is re-written to be used in a new way in ESP-IDF3.0.</b>
*
* Example: write 0x123400 and address_bits=24 to send address of 0x12, 0x34, 0x00 (in previous version, you may have to write 0x12340000).
*/
size_t length; ///< Total data length, in bits
size_t rxlength; ///< Total data length received, should be not greater than ``length`` in full-duplex mode (0 defaults this to the value of ``length``).
void *user; ///< User-defined variable. Can be used to store eg transaction ID.
union {
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
uint8_t tx_data[4]; ///< If SPI_TRANS_USE_TXDATA is set, data set here is sent directly from this variable.
};
union {
void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase. Written by 4 bytes-unit if DMA is used.
uint8_t rx_data[4]; ///< If SPI_TRANS_USE_RXDATA is set, data is received directly to this variable
};
} ; //the rx data should start from a 32-bit aligned address to get around dma issue.
/**
* This struct is for SPI transactions which may change their address and command length.
* Please do set the flags in base to ``SPI_TRANS_VARIABLE_CMD_ADR`` to use the bit length here.
*/
typedef struct {
struct spi_transaction_t base; ///< Transaction data, so that pointer to spi_transaction_t can be converted into spi_transaction_ext_t
uint8_t command_bits; ///< The command length in this transaction, in bits.
uint8_t address_bits; ///< The address length in this transaction, in bits.
uint8_t dummy_bits; ///< The dummy length in this transaction, in bits.
} spi_transaction_ext_t ;
typedef struct spi_device_t* spi_device_handle_t; ///< Handle for a device on a SPI bus
/**
* @brief Allocate a device on a SPI bus
*
* This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master
* peripheral and routes it to the indicated GPIO. All SPI master devices have three CS pins and can thus control
* up to three devices.
*
* @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are
* supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.
*
* @param host_id SPI peripheral to allocate device on
* @param dev_config SPI interface protocol config for the device
* @param handle Pointer to variable to hold the device handle
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_NOT_FOUND if host doesn't have any free CS slots
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_bus_add_device(spi_host_device_t host_id, const spi_device_interface_config_t *dev_config, spi_device_handle_t *handle);
/**
* @brief Remove a device from the SPI bus
*
* @param handle Device handle to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if device already is freed
* - ESP_OK on success
*/
esp_err_t spi_bus_remove_device(spi_device_handle_t handle);
/**
* @brief Queue a SPI transaction for interrupt transaction execution. Get the result by ``spi_device_get_trans_result``.
*
* @note Normally a device cannot start (queue) polling and interrupt
* transactions simultaneously.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param trans_desc Description of transaction to execute
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
* never time out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_TIMEOUT if there was no room in the queue before ticks_to_wait expired
* - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
* - ESP_OK on success
*/
esp_err_t spi_device_queue_trans(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Get the result of a SPI transaction queued earlier by ``spi_device_queue_trans``.
*
* This routine will wait until a transaction to the given device
* succesfully completed. It will then return the description of the
* completed transaction so software can inspect the result and e.g. free the memory or
* re-use the buffers.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param trans_desc Pointer to variable able to contain a pointer to the description of the transaction
that is executed. The descriptor should not be modified until the descriptor is returned by
spi_device_get_trans_result.
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_TIMEOUT if there was no completed transaction before ticks_to_wait expired
* - ESP_OK on success
*/
esp_err_t spi_device_get_trans_result(spi_device_handle_t handle, spi_transaction_t **trans_desc, TickType_t ticks_to_wait);
/**
* @brief Send a SPI transaction, wait for it to complete, and return the result
*
* This function is the equivalent of calling spi_device_queue_trans() followed by spi_device_get_trans_result().
* Do not use this when there is still a transaction separately queued (started) from spi_device_queue_trans() or polling_start/transmit that hasn't been finalized.
*
* @note This function is not thread safe when multiple tasks access the same SPI device.
* Normally a device cannot start (queue) polling and interrupt
* transactions simutanuously.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param trans_desc Description of transaction to execute
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_device_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc);
/**
* @brief Immediately start a polling transaction.
*
* @note Normally a device cannot start (queue) polling and interrupt
* transactions simutanuously. Moreover, a device cannot start a new polling
* transaction if another polling transaction is not finished.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param trans_desc Description of transaction to execute
* @param ticks_to_wait Ticks to wait until there's room in the queue;
* currently only portMAX_DELAY is supported.
*
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_TIMEOUT if the device cannot get control of the bus before ``ticks_to_wait`` expired
* - ESP_ERR_NO_MEM if allocating DMA-capable temporary buffer failed
* - ESP_ERR_INVALID_STATE if previous transactions are not finished
* - ESP_OK on success
*/
esp_err_t spi_device_polling_start(spi_device_handle_t handle, spi_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Poll until the polling transaction ends.
*
* This routine will not return until the transaction to the given device has
* succesfully completed. The task is not blocked, but actively busy-spins for
* the transaction to be completed.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_TIMEOUT if the transaction cannot finish before ticks_to_wait expired
* - ESP_OK on success
*/
esp_err_t spi_device_polling_end(spi_device_handle_t handle, TickType_t ticks_to_wait);
/**
* @brief Send a polling transaction, wait for it to complete, and return the result
*
* This function is the equivalent of calling spi_device_polling_start() followed by spi_device_polling_end().
* Do not use this when there is still a transaction that hasn't been finalized.
*
* @note This function is not thread safe when multiple tasks access the same SPI device.
* Normally a device cannot start (queue) polling and interrupt
* transactions simutanuously.
*
* @param handle Device handle obtained using spi_host_add_dev
* @param trans_desc Description of transaction to execute
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_device_polling_transmit(spi_device_handle_t handle, spi_transaction_t *trans_desc);
/**
* @brief Occupy the SPI bus for a device to do continuous transactions.
*
* Transactions to all other devices will be put off until ``spi_device_release_bus`` is called.
*
* @note The function will wait until all the existing transactions have been sent.
*
* @param device The device to occupy the bus.
* @param wait Time to wait before the the bus is occupied by the device. Currently MUST set to portMAX_DELAY.
*
* @return
* - ESP_ERR_INVALID_ARG : ``wait`` is not set to portMAX_DELAY.
* - ESP_OK : Success.
*/
esp_err_t spi_device_acquire_bus(spi_device_handle_t device, TickType_t wait);
/**
* @brief Release the SPI bus occupied by the device. All other devices can start sending transactions.
*
* @param dev The device to release the bus.
*/
void spi_device_release_bus(spi_device_handle_t dev);
/**
* @brief Calculate the working frequency that is most close to desired frequency, and also the register value.
*
* @param fapb The frequency of apb clock, should be ``APB_CLK_FREQ``.
* @param hz Desired working frequency
* @param duty_cycle Duty cycle of the spi clock
* @param reg_o Output of value to be set in clock register, or NULL if not needed.
*
* @deprecated The app shouldn't care about the register. Call ``spi_get_actual_clock`` instead.
*
* @return Actual working frequency that most fit.
*/
int spi_cal_clock(int fapb, int hz, int duty_cycle, uint32_t* reg_o) __attribute__((deprecated));
/**
* @brief Calculate the working frequency that is most close to desired frequency.
*
* @param fapb The frequency of apb clock, should be ``APB_CLK_FREQ``.
* @param hz Desired working frequency
* @param duty_cycle Duty cycle of the spi clock
*
* @return Actual working frequency that most fit.
*/
int spi_get_actual_clock(int fapb, int hz, int duty_cycle);
/**
* @brief Calculate the timing settings of specified frequency and settings.
*
* @param gpio_is_used True if using GPIO matrix, or False if iomux pins are used.
* @param input_delay_ns Input delay from SCLK launch edge to MISO data valid.
* @param eff_clk Effective clock frequency (in Hz) from spi_cal_clock.
* @param dummy_o Address of dummy bits used output. Set to NULL if not needed.
* @param cycles_remain_o Address of cycles remaining (after dummy bits are used) output.
* - -1 If too many cycles remaining, suggest to compensate half a clock.
* - 0 If no remaining cycles or dummy bits are not used.
* - positive value: cycles suggest to compensate.
*
* @note If **dummy_o* is not zero, it means dummy bits should be applied in half duplex mode, and full duplex mode may not work.
*/
void spi_get_timing(bool gpio_is_used, int input_delay_ns, int eff_clk, int* dummy_o, int* cycles_remain_o);
/**
* @brief Get the frequency limit of current configurations.
* SPI master working at this limit is OK, while above the limit, full duplex mode and DMA will not work,
* and dummy bits will be aplied in the half duplex mode.
*
* @param gpio_is_used True if using GPIO matrix, or False if native pins are used.
* @param input_delay_ns Input delay from SCLK launch edge to MISO data valid.
* @return Frequency limit of current configurations.
*/
int spi_get_freq_limit(bool gpio_is_used, int input_delay_ns);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,198 @@
// 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.
#ifndef _DRIVER_SPI_SLAVE_H_
#define _DRIVER_SPI_SLAVE_H_
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/spi_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define SPI_SLAVE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_SLAVE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
#define SPI_SLAVE_BIT_LSBFIRST (SPI_SLAVE_TXBIT_LSBFIRST|SPI_SLAVE_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
typedef struct spi_slave_transaction_t spi_slave_transaction_t;
typedef void(*slave_transaction_cb_t)(spi_slave_transaction_t *trans);
/**
* @brief This is a configuration for a SPI host acting as a slave device.
*/
typedef struct {
int spics_io_num; ///< CS GPIO pin for this device
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_* flags
int queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_queue_trans but not yet finished using spi_slave_get_trans_result) at the same time
uint8_t mode; /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:
- 0: (0, 0)
- 1: (0, 1)
- 2: (1, 0)
- 3: (1, 1)
*/
slave_transaction_cb_t post_setup_cb; /**< Callback called after the SPI registers are loaded with new data.
*
* This callback is called within interrupt
* context should be in IRAM for best
* performance, see "Transferring Speed"
* section in the SPI Master documentation for
* full details. If not, the callback may crash
* during flash operation when the driver is
* initialized with ESP_INTR_FLAG_IRAM.
*/
slave_transaction_cb_t post_trans_cb; /**< Callback called after a transaction is done.
*
* This callback is called within interrupt
* context should be in IRAM for best
* performance, see "Transferring Speed"
* section in the SPI Master documentation for
* full details. If not, the callback may crash
* during flash operation when the driver is
* initialized with ESP_INTR_FLAG_IRAM.
*/
} spi_slave_interface_config_t;
/**
* This structure describes one SPI transaction
*/
struct spi_slave_transaction_t {
size_t length; ///< Total data length, in bits
size_t trans_len; ///< Transaction data length, in bits
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
void *rx_buffer; /**< Pointer to receive buffer, or NULL for no MISO phase.
* When the DMA is anabled, must start at WORD boundary (``rx_buffer%4==0``),
* and has length of a multiple of 4 bytes.
*/
void *user; ///< User-defined variable. Can be used to store eg transaction ID.
};
/**
* @brief Initialize a SPI bus as a slave interface
*
* @warning For now, only supports HSPI and VSPI.
*
* @param host SPI peripheral to use as a SPI slave interface
* @param bus_config Pointer to a spi_bus_config_t struct specifying how the host should be initialized
* @param slave_config Pointer to a spi_slave_interface_config_t struct specifying the details for the slave interface
* @param dma_chan - Selecting a DMA channel for an SPI bus allows transactions on the bus with size only limited by the amount of internal memory.
* - Selecting SPI_DMA_DISABLED limits the size of transactions.
* - Set to SPI_DMA_DISABLED if only the SPI flash uses this bus.
* - Set to SPI_DMA_CH_AUTO to let the driver to allocate the DMA channel.
*
* @warning If a DMA channel is selected, any transmit and receive buffer used should be allocated in
* DMA-capable memory.
*
* @warning The ISR of SPI is always executed on the core which calls this
* function. Never starve the ISR on this core or the SPI transactions will not
* be handled.
*
* @return
* - ESP_ERR_INVALID_ARG if configuration is invalid
* - ESP_ERR_INVALID_STATE if host already is in use
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
* - ESP_ERR_NO_MEM if out of memory
* - ESP_OK on success
*/
esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *bus_config, const spi_slave_interface_config_t *slave_config, spi_dma_chan_t dma_chan);
/**
* @brief Free a SPI bus claimed as a SPI slave interface
*
* @param host SPI peripheral to free
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_ERR_INVALID_STATE if not all devices on the bus are freed
* - ESP_OK on success
*/
esp_err_t spi_slave_free(spi_host_device_t host);
/**
* @brief Queue a SPI transaction for execution
*
* Queues a SPI transaction to be executed by this slave device. (The transaction queue size was specified when the slave
* device was initialised via spi_slave_initialize.) This function may block if the queue is full (depending on the
* ticks_to_wait parameter). No SPI operation is directly initiated by this function, the next queued transaction
* will happen when the master initiates a SPI transaction by pulling down CS and sending out clock signals.
*
* This function hands over ownership of the buffers in ``trans_desc`` to the SPI slave driver; the application is
* not to access this memory until ``spi_slave_queue_trans`` is called to hand ownership back to the application.
*
* @param host SPI peripheral that is acting as a slave
* @param trans_desc Description of transaction to execute. Not const because we may want to write status back
* into the transaction description.
* @param ticks_to_wait Ticks to wait until there's room in the queue; use portMAX_DELAY to
* never time out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_slave_queue_trans(spi_host_device_t host, const spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait);
/**
* @brief Get the result of a SPI transaction queued earlier
*
* This routine will wait until a transaction to the given device (queued earlier with
* spi_slave_queue_trans) has succesfully completed. It will then return the description of the
* completed transaction so software can inspect the result and e.g. free the memory or
* re-use the buffers.
*
* It is mandatory to eventually use this function for any transaction queued by ``spi_slave_queue_trans``.
*
* @param host SPI peripheral to that is acting as a slave
* @param[out] trans_desc Pointer to variable able to contain a pointer to the description of the
* transaction that is executed
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
* out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_slave_get_trans_result(spi_host_device_t host, spi_slave_transaction_t **trans_desc, TickType_t ticks_to_wait);
/**
* @brief Do a SPI transaction
*
* Essentially does the same as spi_slave_queue_trans followed by spi_slave_get_trans_result. Do
* not use this when there is still a transaction queued that hasn't been finalized
* using spi_slave_get_trans_result.
*
* @param host SPI peripheral to that is acting as a slave
* @param trans_desc Pointer to variable able to contain a pointer to the description of the
* transaction that is executed. Not const because we may want to write status back
* into the transaction description.
* @param ticks_to_wait Ticks to wait until there's a returned item; use portMAX_DELAY to never time
* out.
* @return
* - ESP_ERR_INVALID_ARG if parameter is invalid
* - ESP_OK on success
*/
esp_err_t spi_slave_transmit(spi_host_device_t host, spi_slave_transaction_t *trans_desc, TickType_t ticks_to_wait);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,214 @@
// Copyright 2010-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_types.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "hal/spi_types.h"
#include "driver/spi_common.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C"
{
#endif
#if !SOC_SPI_SUPPORT_SLAVE_HD_VER2 && !CI_HEADER_CHECK
#error The SPI peripheral does not support this feature
#endif
/// Descriptor of data to send/receive
typedef struct {
uint8_t* data; ///< Buffer to send, must be DMA capable
size_t len; ///< Len of data to send/receive. For receiving the buffer length should be multiples of 4 bytes, otherwise the extra part will be truncated.
size_t trans_len; ///< For RX direction, it indicates the data actually received. For TX direction, it is meaningless.
void* arg; ///< Extra argument indiciating this data
} spi_slave_hd_data_t;
/// Information of SPI Slave HD event
typedef struct {
spi_event_t event; ///< Event type
spi_slave_hd_data_t* trans; ///< Corresponding transaction for SPI_EV_SEND and SPI_EV_RECV events
} spi_slave_hd_event_t;
/// Callback for SPI Slave HD
typedef bool (*slave_cb_t)(void* arg, spi_slave_hd_event_t* event, BaseType_t* awoken);
/// Channel of SPI Slave HD to do data transaction
typedef enum {
SPI_SLAVE_CHAN_TX = 0, ///< The output channel (RDDMA)
SPI_SLAVE_CHAN_RX = 1, ///< The input channel (WRDMA)
} spi_slave_chan_t;
/// Callback configuration structure for SPI Slave HD
typedef struct {
slave_cb_t cb_buffer_tx; ///< Callback when master reads from shared buffer
slave_cb_t cb_buffer_rx; ///< Callback when master writes to shared buffer
slave_cb_t cb_sent; ///< Callback when data are sent
slave_cb_t cb_recv; ///< Callback when data are received
slave_cb_t cb_cmd9; ///< Callback when CMD9 received
slave_cb_t cb_cmdA; ///< Callback when CMDA received
void* arg; ///< Argument indicating this SPI Slave HD peripheral instance
} spi_slave_hd_callback_config_t;
//flags for ``spi_slave_hd_slot_config_t`` to use
#define SPI_SLAVE_HD_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
#define SPI_SLAVE_HD_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
#define SPI_SLAVE_HD_BIT_LSBFIRST (SPI_SLAVE_HD_TXBIT_LSBFIRST|SPI_SLAVE_HD_RXBIT_LSBFIRST) ///< Transmit and receive LSB first
#define SPI_SLAVE_HD_APPEND_MODE (1<<2) ///< Adopt DMA append mode for transactions. In this mode, users can load(append) DMA descriptors without stopping the DMA
/// Configuration structure for the SPI Slave HD driver
typedef struct {
uint8_t mode; /**< SPI mode, representing a pair of (CPOL, CPHA) configuration:
- 0: (0, 0)
- 1: (0, 1)
- 2: (1, 0)
- 3: (1, 1)
*/
uint32_t spics_io_num; ///< CS GPIO pin for this device
uint32_t flags; ///< Bitwise OR of SPI_SLAVE_HD_* flags
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.
uint32_t queue_size; ///< Transaction queue size. This sets how many transactions can be 'in the air' (queued using spi_slave_hd_queue_trans but not yet finished using spi_slave_hd_get_trans_result) at the same time
spi_dma_chan_t dma_chan; ///< DMA channel to used.
spi_slave_hd_callback_config_t cb_config; ///< Callback configuration
} spi_slave_hd_slot_config_t;
/**
* @brief Initialize the SPI Slave HD driver.
*
* @param host_id The host to use
* @param bus_config Bus configuration for the bus used
* @param config Configuration for the SPI Slave HD driver
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: invalid argument given
* - ESP_ERR_INVALID_STATE: function called in invalid state, may be some resources are already in use
* - ESP_ERR_NOT_FOUND if there is no available DMA channel
* - ESP_ERR_NO_MEM: memory allocation failed
* - or other return value from `esp_intr_alloc`
*/
esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *bus_config,
const spi_slave_hd_slot_config_t *config);
/**
* @brief Deinitialize the SPI Slave HD driver
*
* @param host_id The host to deinitialize the driver
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: if the host_id is not correct
*/
esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id);
/**
* @brief Queue transactions (segment mode)
*
* @param host_id Host to queue the transaction
* @param chan SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
* @param trans Transaction descriptors
* @param timeout Timeout before the data is queued
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: The input argument is invalid. Can be the following reason:
* - The buffer given is not DMA capable
* - The length of data is invalid (not larger than 0, or exceed the max transfer length)
* - The transaction direction is invalid
* - ESP_ERR_TIMEOUT: Cannot queue the data before timeout. Master is still processing previous transaction.
* - ESP_ERR_INVALID_STATE: Function called in invalid state. This API should be called under segment mode.
*/
esp_err_t spi_slave_hd_queue_trans(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t* trans, TickType_t timeout);
/**
* @brief Get the result of a data transaction (segment mode)
*
* @note This API should be called successfully the same times as the ``spi_slave_hd_queue_trans``.
*
* @param host_id Host to queue the transaction
* @param chan Channel to get the result, SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
* @param[out] out_trans Pointer to the transaction descriptor (``spi_slave_hd_data_t``) passed to the driver before. Hardware has finished this transaction. Member ``trans_len`` indicates the actual number of bytes of received data, it's meaningless for TX.
* @param timeout Timeout before the result is got
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: Function is not valid
* - ESP_ERR_TIMEOUT: There's no transaction done before timeout
* - ESP_ERR_INVALID_STATE: Function called in invalid state. This API should be called under segment mode.
*/
esp_err_t spi_slave_hd_get_trans_res(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t **out_trans, TickType_t timeout);
/**
* @brief Read the shared registers
*
* @param host_id Host to read the shared registers
* @param addr Address of register to read, 0 to ``SOC_SPI_MAXIMUM_BUFFER_SIZE-1``
* @param[out] out_data Output buffer to store the read data
* @param len Length to read, not larger than ``SOC_SPI_MAXIMUM_BUFFER_SIZE-addr``
*/
void spi_slave_hd_read_buffer(spi_host_device_t host_id, int addr, uint8_t *out_data, size_t len);
/**
* @brief Write the shared registers
*
* @param host_id Host to write the shared registers
* @param addr Address of register to write, 0 to ``SOC_SPI_MAXIMUM_BUFFER_SIZE-1``
* @param data Buffer holding the data to write
* @param len Length to write, ``SOC_SPI_MAXIMUM_BUFFER_SIZE-addr``
*/
void spi_slave_hd_write_buffer(spi_host_device_t host_id, int addr, uint8_t *data, size_t len);
/**
* @brief Load transactions (append mode)
*
* @note In this mode, user transaction descriptors will be appended to the DMA and the DMA will keep processing the data without stopping
*
* @param host_id Host to load transactions
* @param chan SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
* @param trans Transaction descriptor
* @param timeout Timeout before the transaction is loaded
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: The input argument is invalid. Can be the following reason:
* - The buffer given is not DMA capable
* - The length of data is invalid (not larger than 0, or exceed the max transfer length)
* - The transaction direction is invalid
* - ESP_ERR_TIMEOUT: Master is still processing previous transaction. There is no available transaction for slave to load
* - ESP_ERR_INVALID_STATE: Function called in invalid state. This API should be called under append mode.
*/
esp_err_t spi_slave_hd_append_trans(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t *trans, TickType_t timeout);
/**
* @brief Get the result of a data transaction (append mode)
*
* @note This API should be called the same times as the ``spi_slave_hd_append_trans``
*
* @param host_id Host to load the transaction
* @param chan SPI_SLAVE_CHAN_TX or SPI_SLAVE_CHAN_RX
* @param[out] out_trans Pointer to the transaction descriptor (``spi_slave_hd_data_t``) passed to the driver before. Hardware has finished this transaction. Member ``trans_len`` indicates the actual number of bytes of received data, it's meaningless for TX.
* @param timeout Timeout before the result is got
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_ARG: Function is not valid
* - ESP_ERR_TIMEOUT: There's no transaction done before timeout
* - ESP_ERR_INVALID_STATE: Function called in invalid state. This API should be called under append mode.
*/
esp_err_t spi_slave_hd_get_append_trans_res(spi_host_device_t host_id, spi_slave_chan_t chan, spi_slave_hd_data_t **out_trans, TickType_t timeout);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,456 @@
// 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_err.h"
#include "esp_attr.h"
#include "soc/soc.h"
#include "soc/timer_periph.h"
#include "esp_intr_alloc.h"
#include "hal/timer_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TIMER_BASE_CLK (APB_CLK_FREQ) /*!< Frequency of the clock on the input of the timer groups */
/**
* @brief Interrupt handle callback function. User need to retrun a bool value
* in callback.
*
* @return
* - True Do task yield at the end of ISR
* - False Not do task yield at the end of ISR
*
* @note If you called FreeRTOS functions in callback, you need to return true or false based on
* the retrun value of argument `pxHigherPriorityTaskWoken`.
* For example, `xQueueSendFromISR` is called in callback, if the return value `pxHigherPriorityTaskWoken`
* of any FreeRTOS calls is pdTRUE, return true; otherwise return false.
*/
typedef bool (*timer_isr_t)(void *);
/**
* @brief Interrupt handle, used in order to free the isr after use.
* Aliases to an int handle for now.
*/
typedef intr_handle_t timer_isr_handle_t;
/**
* @brief Read the counter value of hardware timer.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param timer_val Pointer to accept timer counter value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *timer_val);
/**
* @brief Read the counter value of hardware timer, in unit of a given scale.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param time Pointer, type of double*, to accept timer counter value, in seconds.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double *time);
/**
* @brief Set counter value to hardware timer.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param load_val Counter value to write to the hardware timer.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val);
/**
* @brief Start the counter of hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Pause the counter of hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Set counting mode for hardware timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param counter_dir Counting direction of timer, count-up or count-down
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir);
/**
* @brief Enable or disable counter reload function when alarm event occurs.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param reload Counter reload mode.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload);
/**
* @brief Set hardware timer source clock divider. Timer groups clock are divider from APB clock.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param divider Timer clock divider value. The divider's range is from from 2 to 65536.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint32_t divider);
/**
* @brief Set timer alarm value.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_value A 64-bit value to set the alarm value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value);
/**
* @brief Get timer alarm value.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_value Pointer of A 64-bit value to accept the alarm value.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t *alarm_value);
/**
* @brief Enable or disable generation of timer alarm events.
*
* @param group_num Timer group, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param alarm_en To enable or disable timer alarm function.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en);
/**
* @brief Add ISR handle callback for the corresponding timer.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
* @param isr_handler Interrupt handler function, it is a callback function.
* @param arg Parameter for handler function
* @param 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.
*
* @note This ISR handler will be called from an ISR.
* This ISR handler do not need to handle interrupt status, and should be kept short.
* If you want to realize some specific applications or write the whole ISR, you can
* call timer_isr_register(...) to register ISR.
*
* The callback should return a bool value to determine whether need to do YIELD at
* the end of the ISR.
*
* If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_callback_add(timer_group_t group_num, timer_idx_t timer_num, timer_isr_t isr_handler, void *arg, int intr_alloc_flags);
/**
* @brief Remove ISR handle callback for the corresponding timer.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_callback_remove(timer_group_t group_num, timer_idx_t timer_num);
/**
* @brief Register Timer interrupt handler, the handler is an ISR.
* The handler will be attached to the same CPU core that this function is running on.
*
* @param group_num Timer group number
* @param timer_num Timer index of timer group
* @param fn Interrupt handler function.
* @param arg Parameter for handler function
* @param 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.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @note If use this function to reigster ISR, you need to write the whole ISR.
* In the interrupt handler, you need to call timer_spinlock_take(..) before
* your handling, and call timer_spinlock_give(...) after your handling.
*
* If the intr_alloc_flags value ESP_INTR_FLAG_IRAM is set,
* the handler function must be declared with IRAM_ATTR attribute
* and can only call functions in IRAM or ROM. It cannot call other timer APIs.
* Use direct register access to configure timers from inside the ISR in this case.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, void (*fn)(void *), void *arg, int intr_alloc_flags, timer_isr_handle_t *handle);
/** @brief Initializes and configure the timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param config Pointer to timer initialization parameters.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, const timer_config_t *config);
/** @brief Deinitializes the timer.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_deinit(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Get timer configure value.
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index, 0 for hw_timer[0] & 1 for hw_timer[1]
* @param config Pointer of struct to accept timer parameters.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config);
/** @brief Enable timer group interrupt, by enable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_mask Timer interrupt enable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Disable timer group interrupt, by disable mask
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_mask Timer interrupt disable mask.
* - TIMER_INTR_T0: t0 interrupt
* - TIMER_INTR_T1: t1 interrupt
* - TIMER_INTR_WDT: watchdog interrupt
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
/** @brief Enable timer interrupt
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Disable timer interrupt
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Clear timer interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
*/
void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num) __attribute__((deprecated));
/** @brief Clear timer interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
*/
void timer_group_clr_intr_status_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Enable alarm interrupt, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
*/
void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Get the current counter value, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
*
* @return
* - Counter value
*/
uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Set the alarm threshold for the timer, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
* @param alarm_val Alarm threshold.
*
*/
void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val);
/** @brief Enable/disable a counter, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index.
* @param counter_en Enable/disable.
*
*/
void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en);
/** @brief Get the masked interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
*
* @return
* - Interrupt status
*/
timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num) __attribute__((deprecated));
/** @brief Get interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
*
* @return
* - Interrupt status
*/
uint32_t timer_group_get_intr_status_in_isr(timer_group_t group_num);
/** @brief Clear the masked interrupt status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param intr_mask Masked interrupt.
*
*/
void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask) __attribute__((deprecated));
/** @brief Get auto reload enable status, just used in ISR
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
* @param timer_num Timer index
*
* @return
* - True Auto reload enabled
* - False Auto reload disabled
*/
bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num);
/** @brief Take timer spinlock to enter critical protect
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_spinlock_take(timer_group_t group_num);
/** @brief Give timer spinlock to exit critical protect
*
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t timer_spinlock_give(timer_group_t group_num);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,17 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 "driver/touch_sensor.h"

View File

@ -0,0 +1,171 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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_err.h"
#include "esp_intr_alloc.h"
#include "hal/touch_sensor_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize touch module.
* @note If default parameter don't match the usage scenario, it can be changed after this function.
* @return
* - ESP_OK Success
* - ESP_ERR_NO_MEM Touch pad init error
* - ESP_ERR_NOT_SUPPORTED Touch pad is providing current to external XTAL
*/
esp_err_t touch_pad_init(void);
/**
* @brief Un-install touch pad driver.
* @note After this function is called, other touch functions are prohibited from being called.
* @return
* - ESP_OK Success
* - ESP_FAIL Touch pad driver not initialized
*/
esp_err_t touch_pad_deinit(void);
/**
* @brief Initialize touch pad GPIO
* @param touch_num touch pad index
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if argument is wrong
*/
esp_err_t touch_pad_io_init(touch_pad_t touch_num);
/**
* @brief Set touch sensor high voltage threshold of chanrge.
* The touch sensor measures the channel capacitance value by charging and discharging the channel.
* So the high threshold should be less than the supply voltage.
* @param refh the value of DREFH
* @param refl the value of DREFL
* @param atten the attenuation on DREFH
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if argument is wrong
*/
esp_err_t touch_pad_set_voltage(touch_high_volt_t refh, touch_low_volt_t refl, touch_volt_atten_t atten);
/**
* @brief Get touch sensor reference voltage,
* @param refh pointer to accept DREFH value
* @param refl pointer to accept DREFL value
* @param atten pointer to accept the attenuation on DREFH
* @return
* - ESP_OK on success
*/
esp_err_t touch_pad_get_voltage(touch_high_volt_t *refh, touch_low_volt_t *refl, touch_volt_atten_t *atten);
/**
* @brief Set touch sensor charge/discharge speed for each pad.
* If the slope is 0, the counter would always be zero.
* If the slope is 1, the charging and discharging would be slow, accordingly.
* If the slope is set 7, which is the maximum value, the charging and discharging would be fast.
* @note The higher the charge and discharge current, the greater the immunity of the touch channel,
* but it will increase the system power consumption.
* @param touch_num touch pad index
* @param slope touch pad charge/discharge speed
* @param opt the initial voltage
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if argument is wrong
*/
esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope, touch_tie_opt_t opt);
/**
* @brief Get touch sensor charge/discharge speed for each pad
* @param touch_num touch pad index
* @param slope pointer to accept touch pad charge/discharge slope
* @param opt pointer to accept the initial voltage
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if argument is wrong
*/
esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope, touch_tie_opt_t *opt);
/**
* @brief Deregister the handler previously registered using touch_pad_isr_handler_register
* @param fn handler function to call (as passed to touch_pad_isr_handler_register)
* @param arg argument of the handler (as passed to touch_pad_isr_handler_register)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if a handler matching both fn and
* arg isn't registered
*/
esp_err_t touch_pad_isr_deregister(void(*fn)(void *), void *arg);
/**
* @brief Get the touch pad which caused wakeup from deep sleep.
* @param pad_num pointer to touch pad which caused wakeup
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG parameter is NULL
*/
esp_err_t touch_pad_get_wakeup_status(touch_pad_t *pad_num);
/**
* @brief Set touch sensor FSM mode, the test action can be triggered by the timer,
* as well as by the software.
* @param mode FSM mode
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if argument is wrong
*/
esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode);
/**
* @brief Get touch sensor FSM mode
* @param mode pointer to accept FSM mode
* @return
* - ESP_OK on success
*/
esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode);
/**
* @brief To clear the touch sensor channel active status.
*
* @note The FSM automatically updates the touch sensor status. It is generally not necessary to call this API to clear the status.
* @return
* - ESP_OK on success
*/
esp_err_t touch_pad_clear_status(void);
/**
* @brief Get the touch sensor channel active status mask.
* The bit position represents the channel number. The 0/1 status of the bit represents the trigger status.
*
* @return
* - The touch sensor status. e.g. Touch1 trigger status is `status_mask & (BIT1)`.
*/
uint32_t touch_pad_get_status(void);
/**
* @brief Check touch sensor measurement status.
*
* @return
* - True measurement is under way
* - False measurement done
*/
bool touch_pad_meas_is_done(void);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,352 @@
// Copyright 2015-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
#ifdef __cplusplus
extern "C" {
#endif
#include "soc/soc_caps.h"
#if SOC_TWAI_SUPPORTED
#include "freertos/FreeRTOS.h"
#include "esp_types.h"
#include "esp_intr_alloc.h"
#include "esp_err.h"
#include "gpio.h"
#include "hal/twai_types.h"
/* -------------------- Default initializers and flags ---------------------- */
/** @cond */ //Doxy command to hide preprocessor definitions from docs
/**
* @brief Initializer macro for general configuration structure.
*
* This initializer macros allows the TX GPIO, RX GPIO, and operating mode to be
* configured. The other members of the general configuration structure are
* assigned default values.
*/
#define TWAI_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode) {.mode = op_mode, .tx_io = tx_io_num, .rx_io = rx_io_num, \
.clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED, \
.tx_queue_len = 5, .rx_queue_len = 5, \
.alerts_enabled = TWAI_ALERT_NONE, .clkout_divider = 0, \
.intr_flags = ESP_INTR_FLAG_LEVEL1}
/**
* @brief Alert flags
*
* The following flags represents the various kind of alerts available in
* the TWAI driver. These flags can be used when configuring/reconfiguring
* alerts, or when calling twai_read_alerts().
*
* @note The TWAI_ALERT_AND_LOG flag is not an actual alert, but will configure
* the TWAI driver to log to UART when an enabled alert occurs.
*/
#define TWAI_ALERT_TX_IDLE 0x00000001 /**< Alert(1): No more messages to transmit */
#define TWAI_ALERT_TX_SUCCESS 0x00000002 /**< Alert(2): The previous transmission was successful */
#define TWAI_ALERT_BELOW_ERR_WARN 0x00000004 /**< Alert(4): Both error counters have dropped below error warning limit */
#define TWAI_ALERT_ERR_ACTIVE 0x00000008 /**< Alert(8): TWAI controller has become error active */
#define TWAI_ALERT_RECOVERY_IN_PROGRESS 0x00000010 /**< Alert(16): TWAI controller is undergoing bus recovery */
#define TWAI_ALERT_BUS_RECOVERED 0x00000020 /**< Alert(32): TWAI controller has successfully completed bus recovery */
#define TWAI_ALERT_ARB_LOST 0x00000040 /**< Alert(64): The previous transmission lost arbitration */
#define TWAI_ALERT_ABOVE_ERR_WARN 0x00000080 /**< Alert(128): One of the error counters have exceeded the error warning limit */
#define TWAI_ALERT_BUS_ERROR 0x00000100 /**< Alert(256): A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus */
#define TWAI_ALERT_TX_FAILED 0x00000200 /**< Alert(512): The previous transmission has failed (for single shot transmission) */
#define TWAI_ALERT_RX_QUEUE_FULL 0x00000400 /**< Alert(1024): The RX queue is full causing a frame to be lost */
#define TWAI_ALERT_ERR_PASS 0x00000800 /**< Alert(2048): TWAI controller has become error passive */
#define TWAI_ALERT_BUS_OFF 0x00001000 /**< Alert(4096): Bus-off condition occurred. TWAI controller can no longer influence bus */
#define TWAI_ALERT_RX_FIFO_OVERRUN 0x00002000 /**< Alert(8192): An RX FIFO overrun has occurred */
#define TWAI_ALERT_TX_RETRIED 0x00004000 /**< Alert(16384): An message transmission was cancelled and retried due to an errata workaround */
#define TWAI_ALERT_PERIPH_RESET 0x00008000 /**< Alert(32768): The TWAI controller was reset */
#define TWAI_ALERT_ALL 0x0000FFFF /**< Bit mask to enable all alerts during configuration */
#define TWAI_ALERT_NONE 0x00000000 /**< Bit mask to disable all alerts during configuration */
#define TWAI_ALERT_AND_LOG 0x00010000 /**< Bit mask to enable alerts to also be logged when they occur. Note that logging from the ISR is disabled if CONFIG_TWAI_ISR_IN_IRAM is enabled (see docs). */
/** @endcond */
#define TWAI_IO_UNUSED ((gpio_num_t) -1) /**< Marks GPIO as unused in TWAI configuration */
/* ----------------------- Enum and Struct Definitions ---------------------- */
/**
* @brief TWAI driver states
*/
typedef enum {
TWAI_STATE_STOPPED, /**< Stopped state. The TWAI controller will not participate in any TWAI bus activities */
TWAI_STATE_RUNNING, /**< Running state. The TWAI controller can transmit and receive messages */
TWAI_STATE_BUS_OFF, /**< Bus-off state. The TWAI controller cannot participate in bus activities until it has recovered */
TWAI_STATE_RECOVERING, /**< Recovering state. The TWAI controller is undergoing bus recovery */
} twai_state_t;
/**
* @brief Structure for general configuration of the TWAI driver
*
* @note Macro initializers are available for this structure
*/
typedef struct {
twai_mode_t mode; /**< Mode of TWAI controller */
gpio_num_t tx_io; /**< Transmit GPIO number */
gpio_num_t rx_io; /**< Receive GPIO number */
gpio_num_t clkout_io; /**< CLKOUT GPIO number (optional, set to -1 if unused) */
gpio_num_t bus_off_io; /**< Bus off indicator GPIO number (optional, set to -1 if unused) */
uint32_t tx_queue_len; /**< Number of messages TX queue can hold (set to 0 to disable TX Queue) */
uint32_t rx_queue_len; /**< Number of messages RX queue can hold */
uint32_t alerts_enabled; /**< Bit field of alerts to enable (see documentation) */
uint32_t clkout_divider; /**< CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused) */
int intr_flags; /**< Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_TWAI_ISR_IN_IRAM option should be enabled first. */
} twai_general_config_t;
/**
* @brief Structure to store status information of TWAI driver
*/
typedef struct {
twai_state_t state; /**< Current state of TWAI controller (Stopped/Running/Bus-Off/Recovery) */
uint32_t msgs_to_tx; /**< Number of messages queued for transmission or awaiting transmission completion */
uint32_t msgs_to_rx; /**< Number of messages in RX queue waiting to be read */
uint32_t tx_error_counter; /**< Current value of Transmit Error Counter */
uint32_t rx_error_counter; /**< Current value of Receive Error Counter */
uint32_t tx_failed_count; /**< Number of messages that failed transmissions */
uint32_t rx_missed_count; /**< Number of messages that were lost due to a full RX queue (or errata workaround if enabled) */
uint32_t rx_overrun_count; /**< Number of messages that were lost due to a RX FIFO overrun */
uint32_t arb_lost_count; /**< Number of instances arbitration was lost */
uint32_t bus_error_count; /**< Number of instances a bus error has occurred */
} twai_status_info_t;
/* ------------------------------ Public API -------------------------------- */
/**
* @brief Install TWAI driver
*
* This function installs the TWAI driver using three configuration structures.
* The required memory is allocated and the TWAI driver is placed in the stopped
* state after running this function.
*
* @param[in] g_config General configuration structure
* @param[in] t_config Timing configuration structure
* @param[in] f_config Filter configuration structure
*
* @note Macro initializers are available for the configuration structures (see documentation)
*
* @note To reinstall the TWAI driver, call twai_driver_uninstall() first
*
* @return
* - ESP_OK: Successfully installed TWAI driver
* - ESP_ERR_INVALID_ARG: Arguments are invalid
* - ESP_ERR_NO_MEM: Insufficient memory
* - ESP_ERR_INVALID_STATE: Driver is already installed
*/
esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config);
/**
* @brief Uninstall the TWAI driver
*
* This function uninstalls the TWAI driver, freeing the memory utilized by the
* driver. This function can only be called when the driver is in the stopped
* state or the bus-off state.
*
* @warning The application must ensure that no tasks are blocked on TX/RX
* queues or alerts when this function is called.
*
* @return
* - ESP_OK: Successfully uninstalled TWAI driver
* - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed
*/
esp_err_t twai_driver_uninstall(void);
/**
* @brief Start the TWAI driver
*
* This function starts the TWAI driver, putting the TWAI driver into the running
* state. This allows the TWAI driver to participate in TWAI bus activities such
* as transmitting/receiving messages. The TX and RX queue are reset in this function,
* clearing any messages that are unread or pending transmission. This function
* can only be called when the TWAI driver is in the stopped state.
*
* @return
* - ESP_OK: TWAI driver is now running
* - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed
*/
esp_err_t twai_start(void);
/**
* @brief Stop the TWAI driver
*
* This function stops the TWAI driver, preventing any further message from being
* transmitted or received until twai_start() is called. Any messages in the TX
* queue are cleared. Any messages in the RX queue should be read by the
* application after this function is called. This function can only be called
* when the TWAI driver is in the running state.
*
* @warning A message currently being transmitted/received on the TWAI bus will
* be ceased immediately. This may lead to other TWAI nodes interpreting
* the unfinished message as an error.
*
* @return
* - ESP_OK: TWAI driver is now Stopped
* - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed
*/
esp_err_t twai_stop(void);
/**
* @brief Transmit a TWAI message
*
* This function queues a TWAI message for transmission. Transmission will start
* immediately if no other messages are queued for transmission. If the TX queue
* is full, this function will block until more space becomes available or until
* it times out. If the TX queue is disabled (TX queue length = 0 in configuration),
* this function will return immediately if another message is undergoing
* transmission. This function can only be called when the TWAI driver is in the
* running state and cannot be called under Listen Only Mode.
*
* @param[in] message Message to transmit
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block on the TX queue
*
* @note This function does not guarantee that the transmission is successful.
* The TX_SUCCESS/TX_FAILED alert can be enabled to alert the application
* upon the success/failure of a transmission.
*
* @note The TX_IDLE alert can be used to alert the application when no other
* messages are awaiting transmission.
*
* @return
* - ESP_OK: Transmission successfully queued/initiated
* - ESP_ERR_INVALID_ARG: Arguments are invalid
* - ESP_ERR_TIMEOUT: Timed out waiting for space on TX queue
* - ESP_FAIL: TX queue is disabled and another message is currently transmitting
* - ESP_ERR_INVALID_STATE: TWAI driver is not in running state, or is not installed
* - ESP_ERR_NOT_SUPPORTED: Listen Only Mode does not support transmissions
*/
esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait);
/**
* @brief Receive a TWAI message
*
* This function receives a message from the RX queue. The flags field of the
* message structure will indicate the type of message received. This function
* will block if there are no messages in the RX queue
*
* @param[out] message Received message
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block on RX queue
*
* @warning The flags field of the received message should be checked to determine
* if the received message contains any data bytes.
*
* @return
* - ESP_OK: Message successfully received from RX queue
* - ESP_ERR_TIMEOUT: Timed out waiting for message
* - ESP_ERR_INVALID_ARG: Arguments are invalid
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
*/
esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait);
/**
* @brief Read TWAI driver alerts
*
* This function will read the alerts raised by the TWAI driver. If no alert has
* been issued when this function is called, this function will block until an alert
* occurs or until it timeouts.
*
* @param[out] alerts Bit field of raised alerts (see documentation for alert flags)
* @param[in] ticks_to_wait Number of FreeRTOS ticks to block for alert
*
* @note Multiple alerts can be raised simultaneously. The application should
* check for all alerts that have been enabled.
*
* @return
* - ESP_OK: Alerts read
* - ESP_ERR_TIMEOUT: Timed out waiting for alerts
* - ESP_ERR_INVALID_ARG: Arguments are invalid
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
*/
esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait);
/**
* @brief Reconfigure which alerts are enabled
*
* This function reconfigures which alerts are enabled. If there are alerts
* which have not been read whilst reconfiguring, this function can read those
* alerts.
*
* @param[in] alerts_enabled Bit field of alerts to enable (see documentation for alert flags)
* @param[out] current_alerts Bit field of currently raised alerts. Set to NULL if unused
*
* @return
* - ESP_OK: Alerts reconfigured
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
*/
esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts);
/**
* @brief Start the bus recovery process
*
* This function initiates the bus recovery process when the TWAI driver is in
* the bus-off state. Once initiated, the TWAI driver will enter the recovering
* state and wait for 128 occurrences of the bus-free signal on the TWAI bus
* before returning to the stopped state. This function will reset the TX queue,
* clearing any messages pending transmission.
*
* @note The BUS_RECOVERED alert can be enabled to alert the application when
* the bus recovery process completes.
*
* @return
* - ESP_OK: Bus recovery started
* - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed
*/
esp_err_t twai_initiate_recovery(void);
/**
* @brief Get current status information of the TWAI driver
*
* @param[out] status_info Status information
*
* @return
* - ESP_OK: Status information retrieved
* - ESP_ERR_INVALID_ARG: Arguments are invalid
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
*/
esp_err_t twai_get_status_info(twai_status_info_t *status_info);
/**
* @brief Clear the transmit queue
*
* This function will clear the transmit queue of all messages.
*
* @note The transmit queue is automatically cleared when twai_stop() or
* twai_initiate_recovery() is called.
*
* @return
* - ESP_OK: Transmit queue cleared
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed or TX queue is disabled
*/
esp_err_t twai_clear_transmit_queue(void);
/**
* @brief Clear the receive queue
*
* This function will clear the receive queue of all messages.
*
* @note The receive queue is automatically cleared when twai_start() is
* called.
*
* @return
* - ESP_OK: Transmit queue cleared
* - ESP_ERR_INVALID_STATE: TWAI driver is not installed
*/
esp_err_t twai_clear_receive_queue(void);
#ifdef __cplusplus
}
#endif
#endif //SOC_TWAI_SUPPORTED

View File

@ -0,0 +1,868 @@
// 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 "esp_err.h"
#include "esp_intr_alloc.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "hal/uart_types.h"
// Valid UART port number
#define UART_NUM_0 (0) /*!< UART port 0 */
#define UART_NUM_1 (1) /*!< UART port 1 */
#if SOC_UART_NUM > 2
#define UART_NUM_2 (2) /*!< UART port 2 */
#endif
#define UART_NUM_MAX (SOC_UART_NUM) /*!< UART port max */
#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
#define UART_FIFO_LEN SOC_UART_FIFO_LEN ///< Length of the UART HW FIFO
#define UART_BITRATE_MAX SOC_UART_BITRATE_MAX ///< Maximum configurable bitrate
/**
* @brief UART interrupt configuration parameters for uart_intr_config function
*/
typedef struct {
uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/
uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold (unit: time of sending one byte)*/
uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/
uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/
} uart_intr_config_t;
/**
* @brief UART event types used in the ring buffer
*/
typedef enum {
UART_DATA, /*!< UART data event*/
UART_BREAK, /*!< UART break event*/
UART_BUFFER_FULL, /*!< UART RX buffer full event*/
UART_FIFO_OVF, /*!< UART FIFO overflow event*/
UART_FRAME_ERR, /*!< UART RX frame error event*/
UART_PARITY_ERR, /*!< UART RX parity event*/
UART_DATA_BREAK, /*!< UART TX data and break event*/
UART_PATTERN_DET, /*!< UART pattern detected */
UART_EVENT_MAX, /*!< UART event max index*/
} uart_event_type_t;
/**
* @brief Event structure used in UART event queue
*/
typedef struct {
uart_event_type_t type; /*!< UART event type */
size_t size; /*!< UART data size for UART_DATA event*/
bool timeout_flag; /*!< UART data read timeout flag for UART_DATA event (no new data received during configured RX TOUT)*/
/*!< If the event is caused by FIFO-full interrupt, then there will be no event with the timeout flag before the next byte coming.*/
} uart_event_t;
typedef intr_handle_t uart_isr_handle_t;
/**
* @brief Install UART driver and set the UART to the default configuration.
*
* UART ISR handler will be attached to the same CPU core that this function is running on.
*
* @note Rx_buffer_size should be greater than UART_FIFO_LEN. Tx_buffer_size should be either zero or greater than UART_FIFO_LEN.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param rx_buffer_size UART RX ring buffer size.
* @param tx_buffer_size UART TX ring buffer size.
* If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out.
* @param queue_size UART event queue size/depth.
* @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide
* access to UART events. If set to NULL, driver will not use an event queue.
* @param 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. Do not set ESP_INTR_FLAG_IRAM here
* (the driver's ISR handler is not located in IRAM)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t* uart_queue, int intr_alloc_flags);
/**
* @brief Uninstall UART driver.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_driver_delete(uart_port_t uart_num);
/**
* @brief Checks whether the driver is installed or not
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - true driver is installed
* - false driver is not installed
*/
bool uart_is_driver_installed(uart_port_t uart_num);
/**
* @brief Set UART data bits.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param data_bit UART data bits
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);
/**
* @brief Get the UART data bit configuration.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param data_bit Pointer to accept value of UART data bits.
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success, result will be put in (*data_bit)
*/
esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);
/**
* @brief Set UART stop bits.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param stop_bits UART stop bits
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);
/**
* @brief Get the UART stop bit configuration.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param stop_bits Pointer to accept value of UART stop bits.
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success, result will be put in (*stop_bit)
*/
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);
/**
* @brief Set UART parity mode.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param parity_mode the enum of uart parity configuration
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);
/**
* @brief Get the UART parity mode configuration.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param parity_mode Pointer to accept value of UART parity mode.
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success, result will be put in (*parity_mode)
*
*/
esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
/**
* @brief Set UART baud rate.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param baudrate UART baud rate.
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);
/**
* @brief Get the UART baud rate configuration.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param baudrate Pointer to accept value of UART baud rate
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success, result will be put in (*baudrate)
*
*/
esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
/**
* @brief Set UART line inverse mode
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param inverse_mask Choose the wires that need to be inverted. Using the ORred mask of `uart_signal_inv_t`
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
/**
* @brief Set hardware flow control.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param flow_ctrl Hardware flow control mode
* @param rx_thresh Threshold of Hardware RX flow control (0 ~ UART_FIFO_LEN).
* Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
/**
* @brief Set software flow control.
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param enable switch on or off
* @param rx_thresh_xon low water mark
* @param rx_thresh_xoff high water mark
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff);
/**
* @brief Get the UART hardware flow control configuration.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param flow_ctrl Option for different flow control mode.
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success, result will be put in (*flow_ctrl)
*/
esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);
/**
* @brief Clear UART interrupt status
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param clr_mask Bit mask of the interrupt status to be cleared.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
/**
* @brief Set UART interrupt enable
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param enable_mask Bit mask of the enable bits.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
/**
* @brief Clear UART interrupt enable bits
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param disable_mask Bit mask of the disable bits.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
/**
* @brief Enable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT)
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
/**
* @brief Disable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT)
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
/**
* @brief Disable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT)
*
* @param uart_num UART port number
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
/**
* @brief Enable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT)
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param enable 1: enable; 0: disable
* @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
/**
* @brief Register UART interrupt handler (ISR).
*
* @note UART ISR handler will be attached to the same CPU core that this function is running on.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param fn Interrupt handler function.
* @param arg parameter for handler function
* @param 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.
* @param handle Pointer to return handle. If non-NULL, a handle for the interrupt will
* be returned here.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle);
/**
* @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as
* uart_isr_register was called.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_isr_free(uart_port_t uart_num);
/**
* @brief Set UART pin number
*
* @note Internal signal can be output to multiple GPIO pads.
* Only one GPIO pad can connect with input signal.
*
* @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided
to keep the currently allocated pin.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param tx_io_num UART TX pin GPIO number.
* @param rx_io_num UART RX pin GPIO number.
* @param rts_io_num UART RTS pin GPIO number.
* @param cts_io_num UART CTS pin GPIO number.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);
/**
* @brief Manually set the UART RTS pin level.
* @note UART must be configured with hardware flow control disabled.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param level 1: RTS output low (active); 0: RTS output high (block)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_rts(uart_port_t uart_num, int level);
/**
* @brief Manually set the UART DTR pin level.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param level 1: DTR output low; 0: DTR output high
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
/**
* @brief Set UART idle interval after tx FIFO is empty
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param idle_num idle interval after tx FIFO is empty(unit: the time it takes to send one bit
* under current baudrate)
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint16_t idle_num);
/**
* @brief Set UART configuration parameters.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param uart_config UART parameter settings
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
/**
* @brief Configure UART interrupts.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param intr_conf UART interrupt settings
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);
/**
* @brief Wait until UART TX FIFO is empty.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param ticks_to_wait Timeout, count in RTOS ticks
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
* - ESP_ERR_TIMEOUT Timeout
*/
esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
/**
* @brief Send data to the UART port from a given buffer and length.
*
* This function will not wait for enough space in TX FIFO. It will just fill the available TX FIFO and return when the FIFO is full.
* @note This function should only be used when UART TX buffer is not enabled.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param buffer data buffer address
* @param len data length to send
*
* @return
* - (-1) Parameter error
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
/**
* @brief Send data to the UART port from a given buffer and length,
*
* If the UART driver's parameter 'tx_buffer_size' is set to zero:
* This function will not return until all the data have been sent out, or at least pushed into TX FIFO.
*
* Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
* UART ISR will then move data from the ring buffer to TX FIFO gradually.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param src data buffer address
* @param size data length to send
*
* @return
* - (-1) Parameter error
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_write_bytes(uart_port_t uart_num, const void* src, size_t size);
/**
* @brief Send data to the UART port from a given buffer and length,
*
* If the UART driver's parameter 'tx_buffer_size' is set to zero:
* This function will not return until all the data and the break signal have been sent out.
* After all data is sent out, send a break signal.
*
* Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer,
* UART ISR will then move data from the ring buffer to TX FIFO gradually.
* After all data sent out, send a break signal.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param src data buffer address
* @param size data length to send
* @param brk_len break signal duration(unit: the time it takes to send one bit at current baudrate)
*
* @return
* - (-1) Parameter error
* - OTHERS (>=0) The number of bytes pushed to the TX FIFO
*/
int uart_write_bytes_with_break(uart_port_t uart_num, const void* src, size_t size, int brk_len);
/**
* @brief UART read bytes from UART buffer
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param buf pointer to the buffer.
* @param length data length
* @param ticks_to_wait sTimeout, count in RTOS ticks
*
* @return
* - (-1) Error
* - OTHERS (>=0) The number of bytes read from UART FIFO
*/
int uart_read_bytes(uart_port_t uart_num, void* buf, uint32_t length, TickType_t ticks_to_wait);
/**
* @brief Alias of uart_flush_input.
* UART ring buffer flush. This will discard all data in the UART RX buffer.
* @note Instead of waiting the data sent out, this function will clear UART rx buffer.
* In order to send all the data in tx FIFO, we can use uart_wait_tx_done function.
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_flush(uart_port_t uart_num);
/**
* @brief Clear input buffer, discard all the data is in the ring-buffer.
* @note In order to send all the data in tx FIFO, we can use uart_wait_tx_done function.
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_flush_input(uart_port_t uart_num);
/**
* @brief UART get RX ring buffer cached data length
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param size Pointer of size_t to accept cached data length
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
/**
* @brief UART disable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detects a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num);
#if CONFIG_IDF_TARGET_ESP32
/**
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
* @note This function only works for esp32. And this function is deprecated, please use
* uart_enable_pattern_det_baud_intr instead.
*
* @param uart_num UART port number.
* @param pattern_chr character of the pattern.
* @param chr_num number of the character, 8bit value.
* @param chr_tout timeout of the interval between each pattern characters, 24bit value, unit is APB (80Mhz) clock cycle.
* When the duration is less than this value, it will not take this data as at_cmd char.
* @param post_idle idle time after the last pattern character, 24bit value, unit is APB (80Mhz) clock cycle.
* When the duration is less than this value, it will not take the previous data as the last at_cmd char
* @param pre_idle idle time before the first pattern character, 24bit value, unit is APB (80Mhz) clock cycle.
* When the duration is less than this value, it will not take this data as the first at_cmd char.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle) __attribute__((deprecated));
#endif
/**
* @brief UART enable pattern detect function.
* Designed for applications like 'AT commands'.
* When the hardware detect a series of one same character, the interrupt will be triggered.
*
* @param uart_num UART port number.
* @param pattern_chr character of the pattern.
* @param chr_num number of the character, 8bit value.
* @param chr_tout timeout of the interval between each pattern characters, 16bit value, unit is the baud-rate cycle you configured.
* When the duration is more than this value, it will not take this data as at_cmd char.
* @param post_idle idle time after the last pattern character, 16bit value, unit is the baud-rate cycle you configured.
* When the duration is less than this value, it will not take the previous data as the last at_cmd char
* @param pre_idle idle time before the first pattern character, 16bit value, unit is the baud-rate cycle you configured.
* When the duration is less than this value, it will not take this data as the first at_cmd char.
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t uart_enable_pattern_det_baud_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle);
/**
* @brief Return the nearest detected pattern position in buffer.
* The positions of the detected pattern are saved in a queue,
* this function will dequeue the first pattern position and move the pointer to next pattern position.
* @note If the RX buffer is full and flow control is not enabled,
* the detected pattern may not be found in the rx buffer due to overflow.
*
* The following APIs will modify the pattern position info:
* uart_flush_input, uart_read_bytes, uart_driver_delete, uart_pop_pattern_pos
* It is the application's responsibility to ensure atomic access to the pattern queue and the rx data buffer
* when using pattern detect feature.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @return
* - (-1) No pattern found for current index or parameter error
* - others the pattern position in rx buffer.
*/
int uart_pattern_pop_pos(uart_port_t uart_num);
/**
* @brief Return the nearest detected pattern position in buffer.
* The positions of the detected pattern are saved in a queue,
* This function do nothing to the queue.
* @note If the RX buffer is full and flow control is not enabled,
* the detected pattern may not be found in the rx buffer due to overflow.
*
* The following APIs will modify the pattern position info:
* uart_flush_input, uart_read_bytes, uart_driver_delete, uart_pop_pattern_pos
* It is the application's responsibility to ensure atomic access to the pattern queue and the rx data buffer
* when using pattern detect feature.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @return
* - (-1) No pattern found for current index or parameter error
* - others the pattern position in rx buffer.
*/
int uart_pattern_get_pos(uart_port_t uart_num);
/**
* @brief Allocate a new memory with the given length to save record the detected pattern position in rx buffer.
*
* @param uart_num UART port number, the max port number is (UART_NUM_MAX -1).
* @param queue_length Max queue length for the detected pattern.
* If the queue length is not large enough, some pattern positions might be lost.
* Set this value to the maximum number of patterns that could be saved in data buffer at the same time.
* @return
* - ESP_ERR_NO_MEM No enough memory
* - ESP_ERR_INVALID_STATE Driver not installed
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int queue_length);
/**
* @brief UART set communication mode
*
* @note This function must be executed after uart_driver_install(), when the driver object is initialized.
* @param uart_num Uart number to configure, the max port number is (UART_NUM_MAX -1).
* @param mode UART UART mode to set
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode);
/**
* @brief Set uart threshold value for RX fifo full
* @note If application is using higher baudrate and it is observed that bytes
* in hardware RX fifo are overwritten then this threshold can be reduced
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param threshold Threshold value above which RX fifo full interrupt is generated
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver is not installed
*/
esp_err_t uart_set_rx_full_threshold(uart_port_t uart_num, int threshold);
/**
* @brief Set uart threshold values for TX fifo empty
*
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param threshold Threshold value below which TX fifo empty interrupt is generated
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver is not installed
*/
esp_err_t uart_set_tx_empty_threshold(uart_port_t uart_num, int threshold);
/**
* @brief UART set threshold timeout for TOUT feature
*
* @param uart_num Uart number to configure, the max port number is (UART_NUM_MAX -1).
* @param tout_thresh This parameter defines timeout threshold in uart symbol periods. The maximum value of threshold is 126.
* tout_thresh = 1, defines TOUT interrupt timeout equal to transmission time of one symbol (~11 bit) on current baudrate.
* If the time is expired the UART_RXFIFO_TOUT_INT interrupt is triggered. If tout_thresh == 0,
* the TOUT feature is disabled.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver is not installed
*/
esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh);
/**
* @brief Returns collision detection flag for RS485 mode
* Function returns the collision detection flag into variable pointed by collision_flag.
* *collision_flag = true, if collision detected else it is equal to false.
* This function should be executed when actual transmission is completed (after uart_write_bytes()).
*
* @param uart_num Uart number to configure the max port number is (UART_NUM_MAX -1).
* @param collision_flag Pointer to variable of type bool to return collision flag.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag);
/**
* @brief Set the number of RX pin signal edges for light sleep wakeup
*
* UART can be used to wake up the system from light sleep. This feature works
* by counting the number of positive edges on RX pin and comparing the count to
* the threshold. When the count exceeds the threshold, system is woken up from
* light sleep. This function allows setting the threshold value.
*
* Stop bit and parity bits (if enabled) also contribute to the number of edges.
* For example, letter 'a' with ASCII code 97 is encoded as 0100001101 on the wire
* (with 8n1 configuration), start and stop bits included. This sequence has 3
* positive edges (transitions from 0 to 1). Therefore, to wake up the system
* when 'a' is sent, set wakeup_threshold=3.
*
* The character that triggers wakeup is not received by UART (i.e. it can not
* be obtained from UART FIFO). Depending on the baud rate, a few characters
* after that will also not be received. Note that when the chip enters and exits
* light sleep mode, APB frequency will be changing. To make sure that UART has
* correct baud rate all the time, select REF_TICK as UART clock source,
* by setting use_ref_tick field in uart_config_t to true.
*
* @note in ESP32, the wakeup signal can only be input via IO_MUX (i.e.
* GPIO3 should be configured as function_1 to wake up UART0,
* GPIO9 should be configured as function_5 to wake up UART1), UART2
* does not support light sleep wakeup feature.
*
* @param uart_num UART number, the max port number is (UART_NUM_MAX -1).
* @param wakeup_threshold number of RX edges for light sleep wakeup, value is 3 .. 0x3ff.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if uart_num is incorrect or wakeup_threshold is
* outside of [3, 0x3ff] range.
*/
esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold);
/**
* @brief Get the number of RX pin signal edges for light sleep wakeup.
*
* See description of uart_set_wakeup_threshold for the explanation of UART
* wakeup feature.
*
* @param uart_num UART number, the max port number is (UART_NUM_MAX -1).
* @param[out] out_wakeup_threshold output, set to the current value of wakeup
* threshold for the given UART.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if out_wakeup_threshold is NULL
*/
esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold);
/**
* @brief Wait until UART tx memory empty and the last char send ok (polling mode).
*
* @param uart_num UART number
*
* * @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Driver not installed
*/
esp_err_t uart_wait_tx_idle_polling(uart_port_t uart_num);
/**
* @brief Configure TX signal loop back to RX module, just for the test usage.
*
* @param uart_num UART number
* @param loop_back_en Set ture to enable the loop back function, else set it false.
*
* * @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL Driver not installed
*/
esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en);
/**
* @brief Configure behavior of UART RX timeout interrupt.
*
* When always_rx_timeout is true, timeout interrupt is triggered even if FIFO is full.
* This function can cause extra timeout interrupts triggered only to send the timeout event.
* Call this function only if you want to ensure timeout interrupt will always happen after a byte stream.
*
* @param uart_num UART number
* @param always_rx_timeout_en Set to false enable the default behavior of timeout interrupt,
* set it to true to always trigger timeout interrupt.
*
*/
void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout_en);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,49 @@
// Copyright 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.
#ifndef _UART_SELECT_H_
#define _UART_SELECT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "driver/uart.h"
typedef enum {
UART_SELECT_READ_NOTIF,
UART_SELECT_WRITE_NOTIF,
UART_SELECT_ERROR_NOTIF,
} uart_select_notif_t;
typedef void (*uart_select_notif_callback_t)(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken);
/**
* @brief Set notification callback function for select() events
* @param uart_num UART port number
* @param uart_select_notif_callback callback function
*/
void uart_set_select_notif_callback(uart_port_t uart_num, uart_select_notif_callback_t uart_select_notif_callback);
/**
* @brief Get mutex guarding select() notifications
*/
portMUX_TYPE *uart_get_selectlock(void);
#ifdef __cplusplus
}
#endif
#endif //_UART_SELECT_H_

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.
// Internal header for calibration, don't use in app
#include "sdkconfig.h"
#include "esp_err.h"
#include "hal/adc_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !CONFIG_IDF_TARGET_ESP32
/**
* @brief Calibrate the offset of ADC. (Based on the pre-stored efuse or actual calibration)
*
* @param adc_n ADC unit to calibrate
* @param channel Target channel if really do calibration
* @param atten Attenuation to use
* @return Always ESP_OK
*/
extern esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,284 @@
// 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.
// DO NOT USE THESE APIS IN ANY APPLICATIONS
// GDMA driver is not public for end users, but for ESP-IDF developpers.
#pragma once
#include <stdbool.h>
#include "soc/gdma_channel.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of GDMA channel handle
*
*/
typedef struct gdma_channel_t *gdma_channel_handle_t;
/**
* @brief Enumeration of peripherals which have the DMA capability
* @note Some peripheral might not be available on certain chip, please refer to `soc_caps.h` for detail.
*
*/
typedef enum {
GDMA_TRIG_PERIPH_M2M, /*!< GDMA trigger peripheral: M2M */
GDMA_TRIG_PERIPH_UART, /*!< GDMA trigger peripheral: UART */
GDMA_TRIG_PERIPH_SPI, /*!< GDMA trigger peripheral: SPI */
GDMA_TRIG_PERIPH_I2S, /*!< GDMA trigger peripheral: I2S */
GDMA_TRIG_PERIPH_AES, /*!< GDMA trigger peripheral: AES */
GDMA_TRIG_PERIPH_SHA, /*!< GDMA trigger peripheral: SHA */
GDMA_TRIG_PERIPH_ADC, /*!< GDMA trigger peripheral: ADC */
GDMA_TRIG_PERIPH_DAC, /*!< GDMA trigger peripheral: DAC */
GDMA_TRIG_PERIPH_LCD, /*!< GDMA trigger peripheral: LCD */
GDMA_TRIG_PERIPH_CAM /*!< GDMA trigger peripheral: CAM */
} gdma_trigger_peripheral_t;
/**
* @brief Enumeration of GDMA channel direction
*
*/
typedef enum {
GDMA_CHANNEL_DIRECTION_TX, /*!< GDMA channel direction: TX */
GDMA_CHANNEL_DIRECTION_RX, /*!< GDMA channel direction: RX */
} gdma_channel_direction_t;
/**
* @brief Collection of configuration items that used for allocating GDMA channel
*
*/
typedef struct {
gdma_channel_handle_t sibling_chan; /*!< DMA sibling channel handle (NULL means having sibling is not necessary) */
gdma_channel_direction_t direction; /*!< DMA channel direction */
struct {
int reserve_sibling: 1; /*!< If set, DMA channel allocator would prefer to allocate new channel in a new pair, and reserve sibling channel for future use */
} flags;
} gdma_channel_alloc_config_t;
/**
* @brief Type of GDMA event data
*
*/
typedef struct {
union {
intptr_t rx_eof_desc_addr; /*!< EOF descriptor address of RX channel */
intptr_t tx_eof_desc_addr; /*!< EOF descriptor address of TX channel */
};
} gdma_event_data_t;
/**
* @brief Type of GDMA event callback
* @param dma_chan GDMA channel handle, created from `gdma_new_channel`
* @param event_data GDMA event data
* @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`
*
*/
typedef bool (*gdma_event_callback_t)(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
/**
* @brief Group of supported GDMA TX callbacks
* @note The callbacks are all running under ISR environment
*
*/
typedef struct {
gdma_event_callback_t on_trans_eof; /*!< Invoked when TX engine meets EOF descriptor */
} gdma_tx_event_callbacks_t;
/**
* @brief Group of supported GDMA RX callbacks
* @note The callbacks are all running under ISR environment
*
*/
typedef struct {
gdma_event_callback_t on_recv_eof; /*!< Invoked when RX engine meets EOF descriptor */
} gdma_rx_event_callbacks_t;
/**
* @brief Type of GDMA engine trigger
* @note It's recommended to initialize this structure with `GDMA_MAKE_TRIGGER`.
*
*/
typedef struct {
gdma_trigger_peripheral_t periph; /*!< Target peripheral which will trigger DMA operations */
int instance_id; /*!< Peripheral instance ID. Supported IDs are listed in `soc/gdma_channel.h`, e.g. SOC_GDMA_TRIG_PERIPH_UART0 */
} gdma_trigger_t;
/**
* @brief Helper macro to initialize GDMA trigger
* @note value of `peri` must be selected from `gdma_trigger_peripheral_t` enum.
* e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UART,0)
*
*/
#define GDMA_MAKE_TRIGGER(peri, id) \
(gdma_trigger_t) { .periph = peri, .instance_id = SOC_##peri##id }
/**
* @brief A collection of strategy item that each GDMA channel could apply
*
*/
typedef struct {
bool owner_check; /*!< If set / clear, DMA channel enables / disables checking owner validity */
bool auto_update_desc; /*!< If set / clear, DMA channel enables / disables hardware to update descriptor automatically (TX channel only) */
} gdma_strategy_config_t;
/**
* @brief Create GDMA channel
* @note This API won't install interrupt service for the allocated channel.
* If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`.
*
* @param[in] config Pointer to a collection of configurations for allocating GDMA channel
* @param[out] ret_chan Returnned channel handle
* @return
* - ESP_OK: Create DMA channel successfully
* - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument
* - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory
* - ESP_FAIL: Create DMA channel failed because of other error
*/
esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan);
/**
* @brief Connect GDMA channel to trigger peripheral
*
* @note Suggest to use helper macro `GDMA_MAKE_TRIGGER` to construct parameter `trig_periph`. e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA,0)
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[in] trig_periph GDMA trigger peripheral
* @return
* - ESP_OK: Connect GDMA channel successfully
* - ESP_ERR_INVALID_ARG: Connect GDMA channel failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Connect GDMA channel failed because DMA channel is working with another peripheral
* - ESP_FAIL: Connect GDMA channel failed because of other error
*/
esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_periph);
/**
* @brief Disconnect GMA channel from peripheral
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @return
* - ESP_OK: Disconnect GDMA channel successfully
* - ESP_ERR_INVALID_ARG: Disconnect GDMA channel failed because of invalid argument
* - ESP_ERR_INVALID_STATE: Disconnect GDMA channel failed because DMA channel is not connected to any peripheral
* - ESP_FAIL: Disconnect DMA channel failed because of other error
*/
esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan);
/**
* @brief Apply channel strategy for GDMA channel
*
* @param dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param config Configuration of GDMA channel strategy
* - ESP_OK: Apply channel strategy successfully
* - ESP_ERR_INVALID_ARG: Apply channel strategy failed because of invalid argument
* - ESP_FAIL: Apply channel strategy failed because of other error
*/
esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config);
/**
* @brief Delete GDMA channel
* @note If you call `gdma_new_channel` several times for a same peripheral, make sure you call this API the same times.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @return
* - ESP_OK: Delete GDMA channel successfully
* - ESP_ERR_INVALID_ARG: Delete GDMA channel failed because of invalid argument
* - ESP_FAIL: Delete GDMA channel failed because of other error
*/
esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan);
/**
* @brief Get the channel ID
*
* @note This API breaks the encapsulation of GDMA Channel Object.
* With the returned channel ID, you can even bypass all other GDMA driver API and access Low Level API directly.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[out] channel_id Returned channel ID
* @return
* - ESP_OK: Get GDMA channel ID successfully
* - ESP_ERR_INVALID_ARG: Get GDMA channel ID failed because of invalid argument
* - ESP_FAIL: Get GDMA channel ID failed because of other error
*/
esp_err_t gdma_get_channel_id(gdma_channel_handle_t dma_chan, int *channel_id);
/**
* @brief Set GDMA event callbacks for TX channel
* @note This API will install GDMA interrupt service for the channel internally
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[in] cbs Group of callback functions
* @param[in] user_data User data, which will be passed to callback functions directly
* @return
* - ESP_OK: Set event callbacks successfully
* - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
* - ESP_FAIL: Set event callbacks failed because of other error
*/
esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data);
/**
* @brief Set GDMA event callbacks for RX channel
* @note This API will install GDMA interrupt service for the channel internally
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[in] cbs Group of callback functions
* @param[in] user_data User data, which will be passed to callback functions directly
* @return
* - ESP_OK: Set event callbacks successfully
* - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
* - ESP_FAIL: Set event callbacks failed because of other error
*/
esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_rx_event_callbacks_t *cbs, void *user_data);
/**
* @brief Set DMA descriptor address and start engine
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @param[in] desc_base_addr Base address of descriptors (usually the descriptors are chained into a link or ring)
* @return
* - ESP_OK: Start DMA engine successfully
* - ESP_ERR_INVALID_ARG: Start DMA engine failed because of invalid argument
* - ESP_FAIL: Start DMA engine failed because of other error
*/
esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr);
/**
* @brief Stop DMA engine
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @return
* - ESP_OK: Stop DMA engine successfully
* - ESP_ERR_INVALID_ARG: Stop DMA engine failed because of invalid argument
* - ESP_FAIL: Stop DMA engine failed because of other error
*/
esp_err_t gdma_stop(gdma_channel_handle_t dma_chan);
/**
* @brief Make the appended descriptors be aware to the DMA engine
* @note This API could also resume a paused DMA engine, make sure new descriptors have been appended to the descriptor chain before calling it.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel`
* @return
* - ESP_OK: Send append command to DMA engine successfully
* - ESP_ERR_INVALID_ARG: Send append command to DMA engine failed because of invalid argument
* - ESP_FAIL: Send append command to DMA engine failed because of other error
*/
esp_err_t gdma_append(gdma_channel_handle_t dma_chan);
#ifdef __cplusplus
}
#endif