Merge branch 'master' into feature/modem_sleep
Conflicts: components/esp32/lib
This commit is contained in:
commit
16f2b119eb
184 changed files with 13095 additions and 1632 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -24,3 +24,8 @@ examples/*/build
|
|||
docs/_build/
|
||||
docs/doxygen-warning-log.txt
|
||||
docs/xml/
|
||||
|
||||
# Unit test app files
|
||||
tools/unit-test-app/sdkconfig
|
||||
tools/unit-test-app/sdkconfig.old
|
||||
tools/unit-test-app/build
|
||||
|
|
|
@ -46,6 +46,10 @@ build_template_app:
|
|||
- sed -i.bak -e's/CONFIG_OPTIMIZATION_LEVEL_DEBUG\=y/CONFIG_OPTIMIZATION_LEVEL_RELEASE=y/' sdkconfig
|
||||
- make defconfig
|
||||
- make all V=1
|
||||
# Check if there are any stray printf/ets_printf references in WiFi libs
|
||||
- cd ../components/esp32/lib
|
||||
- test $(xtensa-esp32-elf-nm *.a | grep -w printf | wc -l) -eq 0
|
||||
- test $(xtensa-esp32-elf-nm *.a | grep -w ets_printf | wc -l) -eq 0
|
||||
|
||||
|
||||
.build_gitlab: &build_template
|
||||
|
@ -63,10 +67,7 @@ build_ssc:
|
|||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- ./SSC/build/*.bin
|
||||
- ./SSC/build/*.elf
|
||||
- ./SSC/build/*.map
|
||||
- ./SSC/build/bootloader/*.bin
|
||||
- ./SSC/ssc_bin
|
||||
expire_in: 6 mos
|
||||
|
||||
script:
|
||||
|
@ -81,18 +82,17 @@ build_esp_idf_tests:
|
|||
<<: *build_template
|
||||
artifacts:
|
||||
paths:
|
||||
- ./esp-idf-tests/build/*.bin
|
||||
- ./esp-idf-tests/build/*.elf
|
||||
- ./esp-idf-tests/build/*.map
|
||||
- ./esp-idf-tests/build/bootloader/*.bin
|
||||
- ./tools/unit-test-app/build/*.bin
|
||||
- ./tools/unit-test-app/build/*.elf
|
||||
- ./tools/unit-test-app/build/*.map
|
||||
- ./tools/unit-test-app/build/bootloader/*.bin
|
||||
expire_in: 6 mos
|
||||
|
||||
script:
|
||||
- git clone $GITLAB_SSH_SERVER/idf/esp-idf-tests.git
|
||||
- cd esp-idf-tests
|
||||
- cd tools/unit-test-app
|
||||
- git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..."
|
||||
- make defconfig
|
||||
- make
|
||||
- make TESTS_ALL=1
|
||||
|
||||
build_examples:
|
||||
<<: *build_template
|
||||
|
@ -134,7 +134,7 @@ test_nvs_on_host:
|
|||
tags:
|
||||
- nvs_host_test
|
||||
script:
|
||||
- cd components/nvs_flash/test
|
||||
- cd components/nvs_flash/test_nvs_host
|
||||
- make test
|
||||
|
||||
test_build_system:
|
||||
|
@ -233,7 +233,7 @@ deploy_docs:
|
|||
variables:
|
||||
# LOCAL_ENV_CONFIG_PATH: define in template and jobs can overwrite if required
|
||||
LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF
|
||||
BIN_PATH: "$CI_PROJECT_DIR/SSC/build/"
|
||||
BIN_PATH: "$CI_PROJECT_DIR/SSC/ssc_bin/SSC"
|
||||
APP_NAME: "ssc"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
# append test level folder to TEST_CASE_FILE_PATH in before_script of test job
|
||||
|
@ -292,7 +292,7 @@ deploy_docs:
|
|||
variables:
|
||||
# jobs MUST set CONFIG_FILE in before_script, and overwrite the variables above if necessary
|
||||
LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF
|
||||
BIN_PATH: "$CI_PROJECT_DIR/esp-idf-tests/build/"
|
||||
BIN_PATH: "$CI_PROJECT_DIR/tools/unit-test-app/build/"
|
||||
LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
|
||||
APP_NAME: "ut"
|
||||
TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test/unit_test"
|
||||
|
|
|
@ -15,7 +15,9 @@ Before sending us a Pull Request, please consider this list of points:
|
|||
|
||||
* Is the contribution entirely your own work, or already licensed under an Apache License 2.0 compatible Open Source License? If not then we unfortunately cannot accept it.
|
||||
|
||||
* Does any new code conform to the esp-idf Style Guide? (Style Guide currently pending).
|
||||
* Does any new code conform to the esp-idf :doc:`Style Guide <style-guide>`?
|
||||
|
||||
* Does the code documentation follow requirements in :doc:`documenting-code`?
|
||||
|
||||
* Is the code adequately commented for people to understand how it is structured?
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
|
|||
|
||||
# Custom recursive make for bootloader sub-project
|
||||
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
|
||||
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR)
|
||||
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS=
|
||||
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
typedef SHA_CTX sha_context;
|
||||
#else
|
||||
#include "hwcrypto/sha.h"
|
||||
typedef esp_sha_context sha_context;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
|
@ -42,7 +41,9 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver
|
|||
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||
{
|
||||
sha_context sha;
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
SHA_CTX sha;
|
||||
#endif
|
||||
uint8_t digest[32];
|
||||
ptrdiff_t keylen;
|
||||
const uint8_t *data;
|
||||
|
@ -83,12 +84,8 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
|||
ets_sha_finish(&sha, SHA2_256, digest);
|
||||
ets_sha_disable();
|
||||
#else
|
||||
/* Use thread-safe esp-idf SHA layer */
|
||||
esp_sha256_init(&sha);
|
||||
esp_sha256_start(&sha, false);
|
||||
esp_sha256_update(&sha, data, length);
|
||||
esp_sha256_finish(&sha, digest);
|
||||
esp_sha256_free(&sha);
|
||||
/* Use thread-safe esp-idf SHA function */
|
||||
esp_sha(SHA2_256, data, length, digest);
|
||||
#endif
|
||||
|
||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||
|
|
|
@ -115,7 +115,7 @@ static struct osi_funcs_t osi_funcs = {
|
|||
._mutex_create = mutex_create_wrapper,
|
||||
._mutex_lock = mutex_lock_wrapper,
|
||||
._mutex_unlock = mutex_unlock_wrapper,
|
||||
._read_efuse_mac = system_efuse_read_mac,
|
||||
._read_efuse_mac = esp_efuse_read_mac,
|
||||
};
|
||||
|
||||
static void bt_controller_task(void *pvParam)
|
||||
|
|
|
@ -321,9 +321,9 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
|
|||
}
|
||||
if(pGPIOConfig->pull_up_en) {
|
||||
pu_en = 1;
|
||||
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||
REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pu);
|
||||
} else {
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
|
||||
REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pu);
|
||||
}
|
||||
if(pGPIOConfig->pull_down_en) {
|
||||
pd_en = 1;
|
||||
|
|
359
components/driver/include/driver/pcnt.h
Normal file
359
components/driver/include/driver/pcnt.h
Normal file
|
@ -0,0 +1,359 @@
|
|||
#ifndef __PCNT_H__
|
||||
#define __PCNT_H__
|
||||
|
||||
#include <esp_types.h>
|
||||
#include "esp_intr.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/pcnt_reg.h"
|
||||
#include "soc/pcnt_struct.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PCNT_PIN_NOT_USED (-1) /*!< Pin are not used */
|
||||
|
||||
typedef enum {
|
||||
PCNT_MODE_KEEP = 0, /*!< Control mode: won't change counter mode*/
|
||||
PCNT_MODE_REVERSE = 1, /*!< Control mode: invert counter mode(increase -> decrease, decrease -> increase);*/
|
||||
PCNT_MODE_DISABLE = 2, /*!< Control mode: Inhibit counter(counter value will not change in this condition)*/
|
||||
PCNT_MODE_MAX
|
||||
} pcnt_ctrl_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PCNT_COUNT_DIS = 0, /*!< Counter mode: Decrease counter value*/
|
||||
PCNT_COUNT_INC = 1, /*!< Counter mode: Increase counter value*/
|
||||
PCNT_COUNT_DEC = 2, /*!< Counter mode: Inhibit counter(counter value will not change in this condition)*/
|
||||
PCNT_COUNT_MAX
|
||||
} pcnt_count_mode_t;
|
||||
|
||||
typedef enum {
|
||||
PCNT_UNIT_0 = 0, /*!< PCNT unit0 */
|
||||
PCNT_UNIT_1 = 1, /*!< PCNT unit1 */
|
||||
PCNT_UNIT_2 = 2, /*!< PCNT unit2 */
|
||||
PCNT_UNIT_3 = 3, /*!< PCNT unit3 */
|
||||
PCNT_UNIT_4 = 4, /*!< PCNT unit4 */
|
||||
PCNT_UNIT_5 = 5, /*!< PCNT unit5 */
|
||||
PCNT_UNIT_6 = 6, /*!< PCNT unit6 */
|
||||
PCNT_UNIT_7 = 7, /*!< PCNT unit7 */
|
||||
PCNT_UNIT_MAX,
|
||||
} pcnt_unit_t;
|
||||
|
||||
typedef enum{
|
||||
PCNT_CHANNEL_0 = 0x00, /*!< PCNT channel0 */
|
||||
PCNT_CHANNEL_1 = 0x01, /*!< PCNT channel1 */
|
||||
PCNT_CHANNEL_MAX,
|
||||
} pcnt_channel_t;
|
||||
|
||||
typedef enum {
|
||||
PCNT_EVT_L_LIM = 0, /*!< PCNT watch point event: Minimum counter value */
|
||||
PCNT_EVT_H_LIM = 1, /*!< PCNT watch point event: Maximum counter value*/
|
||||
PCNT_EVT_THRES_0 = 2, /*!< PCNT watch point event: threshold0 value event*/
|
||||
PCNT_EVT_THRES_1 = 3, /*!< PCNT watch point event: threshold1 value event*/
|
||||
PCNT_EVT_ZERO = 4, /*!< PCNT watch point event: counter value zero event*/
|
||||
PCNT_EVT_MAX
|
||||
} pcnt_evt_type_t;
|
||||
|
||||
/**
|
||||
* @brief Pulse Counter configure struct
|
||||
*/
|
||||
typedef struct {
|
||||
int pulse_gpio_num; /*!< Pulse input gpio_num, if you want to use gpio16, pulse_gpio_num = 16, a negative value will be ignored */
|
||||
int ctrl_gpio_num; /*!< Contol signal input gpio_num, a negative value will be ignored*/
|
||||
pcnt_ctrl_mode_t lctrl_mode; /*!< PCNT low control mode*/
|
||||
pcnt_ctrl_mode_t hctrl_mode; /*!< PCNT high control mode*/
|
||||
pcnt_count_mode_t pos_mode; /*!< PCNT positive edge count mode*/
|
||||
pcnt_count_mode_t neg_mode; /*!< PCNT negative edge count mode*/
|
||||
int16_t counter_h_lim; /*!< Maximum counter value */
|
||||
int16_t counter_l_lim; /*!< Minimum counter value */
|
||||
pcnt_unit_t unit; /*!< PCNT unit number */
|
||||
pcnt_channel_t channel; /*!< the PCNT channel */
|
||||
} pcnt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Configure Pulse Counter unit
|
||||
*
|
||||
* @param pcnt_config Pointer of Pulse Counter unit configure parameter
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t pcnt_unit_config(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_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_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_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_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_ARG Parameter error
|
||||
*/
|
||||
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit);
|
||||
|
||||
/**
|
||||
* @brief Disable PCNT interrupt for PCNT uint
|
||||
*
|
||||
* @param pcnt_unit PCNT unit number
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - 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_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_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_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_ARG Parameter error
|
||||
*/
|
||||
esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value);
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @note
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
*
|
||||
* @param pcnt_intr_num PCNT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @param fn Interrupt handler function.
|
||||
* @note
|
||||
* Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*/
|
||||
esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fn)(void*), void * arg);
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @note
|
||||
* Set to PCNT_PIN_NOT_USED if unused.
|
||||
* @param ctrl_io Control signal input GPIO
|
||||
* @note
|
||||
* Set to PCNT_PIN_NOT_USED if unused.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - 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_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_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_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_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_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);
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
|
||||
#endif
|
|
@ -39,6 +39,8 @@ typedef enum {
|
|||
PERIPH_PWM3_MODULE,
|
||||
PERIPH_UHCI0_MODULE,
|
||||
PERIPH_UHCI1_MODULE,
|
||||
PERIPH_RMT_MODULE,
|
||||
PERIPH_PCNT_MODULE,
|
||||
} periph_module_t;
|
||||
|
||||
/**
|
||||
|
|
794
components/driver/include/driver/rmt.h
Normal file
794
components/driver/include/driver/rmt.h
Normal file
|
@ -0,0 +1,794 @@
|
|||
// 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_RMT_CTRL_H_
|
||||
#define _DRIVER_RMT_CTRL_H_
|
||||
#include "esp_err.h"
|
||||
#include "soc/rmt_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RMT_MEM_BLOCK_BYTE_NUM (256)
|
||||
#define RMT_MEM_ITEM_NUM (RMT_MEM_BLOCK_BYTE_NUM/4)
|
||||
|
||||
typedef enum {
|
||||
RMT_CHANNEL_0=0, /*!< RMT Channel0 */
|
||||
RMT_CHANNEL_1, /*!< RMT Channel1 */
|
||||
RMT_CHANNEL_2, /*!< RMT Channel2 */
|
||||
RMT_CHANNEL_3, /*!< RMT Channel3 */
|
||||
RMT_CHANNEL_4, /*!< RMT Channel4 */
|
||||
RMT_CHANNEL_5, /*!< RMT Channel5 */
|
||||
RMT_CHANNEL_6, /*!< RMT Channel6 */
|
||||
RMT_CHANNEL_7, /*!< RMT Channel7 */
|
||||
RMT_CHANNEL_MAX
|
||||
} rmt_channel_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_MEM_OWNER_TX = 0, /*!< RMT RX mode, RMT transmitter owns the memory block*/
|
||||
RMT_MEM_OWNER_RX = 1, /*!< RMT RX mode, RMT receiver owns the memory block*/
|
||||
RMT_MEM_OWNER_MAX,
|
||||
}rmt_mem_owner_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_BASECLK_REF = 0, /*!< RMT source clock system reference tick, 1MHz by default(Not supported in this version) */
|
||||
RMT_BASECLK_APB, /*!< RMT source clock is APB CLK, 80Mhz by default */
|
||||
RMT_BASECLK_MAX,
|
||||
} rmt_source_clk_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_DATA_MODE_FIFO = 0, /*<! RMT memory access in FIFO mode */
|
||||
RMT_DATA_MODE_MEM = 1, /*<! RMT memory access in memory mode */
|
||||
RMT_DATA_MODE_MAX,
|
||||
} rmt_data_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_MODE_TX=0, /*!< RMT TX mode */
|
||||
RMT_MODE_RX, /*!< RMT RX mode */
|
||||
RMT_MODE_MAX
|
||||
} rmt_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_IDLE_LEVEL_LOW=0, /*!< RMT TX idle level: low Level */
|
||||
RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */
|
||||
RMT_IDLE_LEVEL_MAX,
|
||||
} rmt_idle_level_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_CARRIER_LEVEL_LOW=0, /*!< RMT carrier wave is modulated for low Level output */
|
||||
RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */
|
||||
RMT_CARRIER_LEVEL_MAX
|
||||
} rmt_carrier_level_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT TX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool loop_en; /*!< RMT loop output mode*/
|
||||
uint32_t carrier_freq_hz; /*!< RMT carrier frequency */
|
||||
uint8_t carrier_duty_percent; /*!< RMT carrier duty (%) */
|
||||
rmt_carrier_level_t carrier_level; /*!< RMT carrier level */
|
||||
bool carrier_en; /*!< RMT carrier enable */
|
||||
rmt_idle_level_t idle_level; /*!< RMT idle level */
|
||||
bool idle_output_en; /*!< RMT idle level output enable*/
|
||||
}rmt_tx_config_t;
|
||||
|
||||
/**
|
||||
* @brief Data struct of RMT RX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool filter_en; /*!< RMT receiver filer enable*/
|
||||
uint8_t filter_ticks_thresh; /*!< RMT filter tick number */
|
||||
uint16_t idle_threshold; /*!< RMT RX idle threshold */
|
||||
}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 */
|
||||
uint8_t clk_div; /*!< RMT channel counter divider */
|
||||
gpio_num_t gpio_num; /*!< RMT GPIO number */
|
||||
uint8_t mem_block_num; /*!< RMT memory block number */
|
||||
union{
|
||||
rmt_tx_config_t tx_config; /*!< RMT TX parameter */
|
||||
rmt_rx_config_t rx_config; /*!< RMT RX parameter */
|
||||
};
|
||||
} rmt_config_t;
|
||||
|
||||
/**
|
||||
* @brief Set RMT clock divider, channel clock is divided from source clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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.
|
||||
* Channel0 can use at most 8 blocks of memory, accordingly channel7 can only use one memory block.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 channel0-7.
|
||||
*
|
||||
* 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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_rx_stop(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Reset RMT TX/RX memory index.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set RMT memory owner.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @param loop_en To enable RMT transmitter loop sending mode.
|
||||
*
|
||||
* If set true, transmitter will continue sending from the first data
|
||||
* to the last data in channel0-7 again and again.
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @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, channel0-7 will ignore input pulse when the pulse width is smaller than threshold.
|
||||
* Counted in source clock, not divided counter clock.
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 source clock:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz( not supported in this version).
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 source clock:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz( not supported in this version).
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @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 (0-7)
|
||||
*
|
||||
* @param idle_out_en To enable idle level output.
|
||||
*
|
||||
* @param level To set the output signal's level for channel0-7 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 status
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param status Pointer to accept channel status.
|
||||
*
|
||||
* @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 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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Set RMT RX interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @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 (0 - 7)
|
||||
*
|
||||
* @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 (0 - 7)
|
||||
*
|
||||
* @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 event interrupt enable
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @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_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
|
||||
|
||||
/**
|
||||
* @brief Set RMT pins
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Configure RMT parameters
|
||||
*
|
||||
* @param rmt_param RMT parameter structor
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_config(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.
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
* @note
|
||||
* If you already called rmt_driver_install to use system RMT driver,
|
||||
* please do not register ISR handler again.
|
||||
*
|
||||
* @param rmt_intr_num RMT interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
*
|
||||
* @param fn Interrupt handler function.
|
||||
*
|
||||
* @note
|
||||
* the handler function MUST be defined with attribution of "IRAM_ATTR".
|
||||
*
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @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(uint8_t rmt_intr_num, void (* fn)(void* ), void * arg);
|
||||
|
||||
/**
|
||||
* @brief Fill memory data of channel with given RMT items.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @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, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset);
|
||||
|
||||
/**
|
||||
* @brief Initialize RMT driver
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param rx_buf_size Size of RMT RX ringbuffer.
|
||||
*
|
||||
* @note
|
||||
* If we do not need RX ringbuffer, just set rx_buf_size to 0.
|
||||
*
|
||||
* @note
|
||||
* When we call rmt_driver_install function, it will register a driver ISR handler,
|
||||
* DO NOT REGISTER ISR HANDLER AGAIN.
|
||||
*
|
||||
* @param rmt_intr_num RMT interrupt number.
|
||||
*
|
||||
* @return
|
||||
* - 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 rmt_intr_num);
|
||||
|
||||
/**
|
||||
* @brief Uninstall RMT driver.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_driver_uninstall(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief RMT send waveform from rmt_item array.
|
||||
*
|
||||
* This API allows user to send waveform with any length.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param rmt_item head point of RMT items array.
|
||||
*
|
||||
* @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, rmt_item32_t* rmt_item, int item_num, bool wait_tx_done);
|
||||
|
||||
/**
|
||||
* @brief Wait RMT TX finished.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_wait_tx_done(rmt_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Get ringbuffer from UART.
|
||||
*
|
||||
* Users can get the RMT RX ringbuffer handler, and process the RX data.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param buf_handler Pointer to buffer handler to accept RX ringbuffer handler.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_handler);
|
||||
|
||||
/***************************EXAMPLE**********************************
|
||||
*
|
||||
* @note
|
||||
* You can also refer to example/09_rmt_nec_tx_rx to have more information about how to use RMT module.
|
||||
*
|
||||
* ----------------EXAMPLE OF RMT SETTING ---------------------
|
||||
* @code{c}
|
||||
* //1. enable RMT
|
||||
* //enable RMT module, or you can not set any register of it.
|
||||
* //this will be done in rmt_config API.
|
||||
* periph_module_enable(PERIPH_RMT_MODULE);
|
||||
* @endcode
|
||||
*
|
||||
* @code{c}
|
||||
* //2. set RMT transmitter
|
||||
* void rmt_tx_init()
|
||||
* {
|
||||
* rmt_config_t rmt_tx;
|
||||
* rmt_tx.channel = 0;
|
||||
* rmt_tx.gpio_num = 16;
|
||||
* rmt_tx.mem_block_num = 1;
|
||||
* rmt_tx.clk_div = 100;
|
||||
* rmt_tx.tx_config.loop_en = false;
|
||||
* rmt_tx.tx_config.carrier_duty_percent = 50;
|
||||
* rmt_tx.tx_config.carrier_freq_hz = 38000;
|
||||
* rmt_tx.tx_config.carrier_level = 1;
|
||||
* rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
|
||||
* rmt_tx.tx_config.idle_level = 0;
|
||||
* rmt_tx.tx_config.idle_output_en = true;
|
||||
* rmt_tx.rmt_mode = 0;
|
||||
* rmt_config(&rmt_tx);
|
||||
*
|
||||
* //install system RMT driver, disable rx ringbuffer for transmitter.
|
||||
* rmt_driver_install(rmt_tx.channel, 0, RMT_INTR_NUM);
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
* @code{c}
|
||||
* //3. set RMT receiver
|
||||
* void rmt_rx_init()
|
||||
* {
|
||||
* rmt_config_t rmt_rx;
|
||||
* rmt_rx.channel = 1;
|
||||
* rmt_rx.gpio_num = 19;
|
||||
* rmt_rx.clk_div = 100;
|
||||
* rmt_rx.mem_block_num = 1;
|
||||
* rmt_rx.rmt_mode = RMT_MODE_RX;
|
||||
* rmt_rx.rx_config.filter_en = true;
|
||||
* rmt_rx.rx_config.filter_ticks_thresh = 100;
|
||||
* rmt_rx.rx_config.idle_threshold = 0xffff;
|
||||
* rmt_config(&rmt_rx);
|
||||
*
|
||||
* //install system RMT driver.
|
||||
* rmt_driver_install(rmt_rx.channel, 1000, RMT_INTR_NUM);
|
||||
* }
|
||||
*
|
||||
* ----------------EXAMPLE OF RMT INTERRUPT ------------------
|
||||
* @code{c}
|
||||
*
|
||||
* rmt_isr_register(RMT_INTR_NUM, rmt_isr, NULL); //hook the ISR handler for RMT interrupt
|
||||
* @endcode
|
||||
* @note
|
||||
* 0. If you have called rmt_driver_install, you don't need to set ISR handler any more.
|
||||
* 1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
|
||||
* 2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
|
||||
* 3. do not pick the INUM that already occupied by the system.
|
||||
* 4. refer to soc.h to check which INUMs that can be used.
|
||||
*
|
||||
* ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
|
||||
* @code{c}
|
||||
* #include "esp_attr.h"
|
||||
* //we should add 'IRAM_ATTR' attribution when we declare the isr function
|
||||
* void IRAM_ATTR rmt_isr_handler(void* arg)
|
||||
* {
|
||||
* //read RMT interrupt status.
|
||||
* uint32_t intr_st = RMT.int_st.val;
|
||||
*
|
||||
* //you will find which channels have triggered fade_end interrupt here,
|
||||
* //then, you can post some event to RTOS queue to process the event.
|
||||
* //later we will add a queue in the driver code.
|
||||
*
|
||||
* //clear RMT interrupt status.
|
||||
* RMT.int_clr.val = intr_st;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*--------------------------END OF EXAMPLE --------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DRIVER_RMT_CTRL_H_ */
|
349
components/driver/include/driver/timer.h
Normal file
349
components/driver/include/driver/timer.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
// Copyright 2010-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_TIMER_H_
|
||||
#define _DRIVER_TIMER_H_
|
||||
#include "esp_err.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define TIMER_BASE_CLK (APB_CLK_FREQ)
|
||||
/**
|
||||
* @brief Selects a Timer-Group out of 2 available groups
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_GROUP_0 = 0, /*!<Hw timer group 0*/
|
||||
TIMER_GROUP_1 = 1, /*!<Hw timer group 1*/
|
||||
TIMER_GROUP_MAX,
|
||||
} timer_group_t;
|
||||
|
||||
/**
|
||||
* @brief Select a hardware timer from timer groups
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
|
||||
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
|
||||
TIMER_MAX,
|
||||
} timer_idx_t;
|
||||
|
||||
/**
|
||||
* @brief Decides the direction of counter
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_COUNT_DOWN = 0, /*!< Descending Count from cnt.high|cnt.low*/
|
||||
TIMER_COUNT_UP = 1, /*!< Ascending Count from Zero*/
|
||||
TIMER_COUNT_MAX
|
||||
} timer_count_dir_t;
|
||||
|
||||
/**
|
||||
* @brief Decides whether timer is on or paused
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_PAUSE = 0, /*!<Pause timer counter*/
|
||||
TIMER_START = 1, /*!<Start timer counter*/
|
||||
} timer_start_t;
|
||||
|
||||
/**
|
||||
* @brief Decides whether to enable alarm mode
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_ALARM_DIS = 0, /*!< Disable timer alarm*/
|
||||
TIMER_ALARM_EN = 1, /*!< Enable timer alarm*/
|
||||
TIMER_ALARM_MAX
|
||||
} timer_alarm_t;
|
||||
|
||||
/**
|
||||
* @brief Select interrupt type if running in alarm mode.
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_INTR_LEVEL = 0, /*!< Interrupt mode: level mode*/
|
||||
//TIMER_INTR_EDGE = 1, /*!< Interrupt mode: edge mode, Not supported Now*/
|
||||
TIMER_INTR_MAX
|
||||
} timer_intr_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Select if Alarm needs to be loaded by software or automatically reload by hardware.
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_AUTORELOAD_DIS = 0, /*!< Disable auto-reload: hardware will not load counter value after an alarm event*/
|
||||
TIMER_AUTORELOAD_EN = 1, /*!< Enable auto-reload: hardware will load counter value after an alarm event*/
|
||||
TIMER_AUTORELOAD_MAX,
|
||||
} timer_autoreload_t;
|
||||
|
||||
/**
|
||||
* @brief timer configure struct
|
||||
*/
|
||||
typedef struct {
|
||||
bool alarm_en; /*!< Timer alarm enable */
|
||||
bool counter_en; /*!< Counter enable */
|
||||
timer_count_dir_t counter_dir; /*!< Counter direction */
|
||||
timer_intr_mode_t intr_type; /*!< Interrupt mode */
|
||||
bool auto_reload; /*!< Timer auto-reload */
|
||||
uint16_t divider; /*!< Counter clock divider*/
|
||||
} timer_config_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.
|
||||
*
|
||||
* @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, uint16_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 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_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 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.
|
||||
* @note
|
||||
* Users should know that which CPU is running and then pick a INUM that is not used by system.
|
||||
* We can find the information of INUM and interrupt level in soc.h.
|
||||
*
|
||||
* @param group_num Timer group number
|
||||
* @param timer_num Timer index of timer group
|
||||
* @param timer_intr_num TIMER interrupt number, check the info in soc.h, and please see the core-isa.h for more details
|
||||
* @param intr_type Timer interrupt type
|
||||
* @param fn Interrupt handler function.
|
||||
* @note
|
||||
* Code inside the handler function can only call functions in IRAM, so cannot call other timer APIs.
|
||||
* Use direct register access to access timers from inside the ISR.
|
||||
*
|
||||
* @param arg Parameter for handler function
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Function pointer error.
|
||||
*
|
||||
* @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, int timer_intr_num, timer_intr_mode_t intr_type, void (*fn)(void*), void * arg);
|
||||
|
||||
/** @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, timer_config_t* config);
|
||||
|
||||
/** @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 en_mask Timer interrupt enable mask.
|
||||
* Use TIMG_T0_INT_ENA_M to enable t0 interrupt
|
||||
* Use TIMG_T1_INT_ENA_M to enable t1 interrupt
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask);
|
||||
|
||||
/** @brief Disable timer group interrupt, by disable mask
|
||||
*
|
||||
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
|
||||
* @param disable_mask Timer interrupt disable mask.
|
||||
* Use TIMG_T0_INT_ENA_M to disable t0 interrupt
|
||||
* Use TIMG_T1_INT_ENA_M to disable t1 interrupt
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TIMER_H_ */
|
|
@ -167,25 +167,25 @@ esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bi
|
|||
* @brief Set UART stop bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param bit_num UART stop bits
|
||||
* @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 bit_num);
|
||||
esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);
|
||||
|
||||
/**
|
||||
* @brief Set UART stop bits.
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param stop_bit Pointer to accept value of UART stop bits.
|
||||
* @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_bit);
|
||||
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);
|
||||
|
||||
/**
|
||||
* @brief Set UART parity.
|
||||
|
@ -216,13 +216,13 @@ 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_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param baud_rate UART baud-rate.
|
||||
* @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 baud_rate);
|
||||
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);
|
||||
|
||||
/**
|
||||
* @brief Get UART bit-rate.
|
||||
|
@ -241,7 +241,7 @@ esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
|
|||
* @brief Set UART line inverse mode
|
||||
*
|
||||
* @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
|
||||
* @param inverse_mask Choose the wires that need to be inversed.
|
||||
* @param inverse_mask Choose the wires that need to be inverted.
|
||||
* Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.
|
||||
*
|
||||
* @return
|
||||
|
|
|
@ -137,29 +137,32 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
|
|||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if(timer_num > LEDC_TIMER_3) {
|
||||
ESP_LOGE(LEDC_TAG, "Time Select %u", timer_num);
|
||||
ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t precision = (0x1 << bit_num); //2**depth
|
||||
uint64_t div_param = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision; //8bit fragment
|
||||
int timer_clk_src;
|
||||
/*Fail ,because the div_num overflow or too small*/
|
||||
if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { //REF TICK
|
||||
/*Selet the reference tick*/
|
||||
uint32_t precision = (0x1 << bit_num); // 2**depth
|
||||
// Try calculating divisor based on LEDC_APB_CLK
|
||||
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
|
||||
// div_param is a Q10.8 fixed point value
|
||||
uint64_t div_param = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision;
|
||||
if (div_param < 256) {
|
||||
// divisor is too low
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try reducing freq_hz or bit_num. div_param=%d", (uint32_t) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
if (div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", (uint32_t)div_param);
|
||||
if(div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try increasing freq_hz or bit_num. div_param=%d", (uint32_t) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
} else { //APB TICK
|
||||
timer_clk_src = LEDC_APB_CLK;
|
||||
}
|
||||
/*set timer parameters*/
|
||||
/*timer settings decide the clk of counter and the period of PWM*/
|
||||
// set timer parameters
|
||||
ledc_timer_set(speed_mode, timer_num, div_param, bit_num, timer_clk_src);
|
||||
/* reset timer.*/
|
||||
// reset timer
|
||||
ledc_timer_rst(speed_mode, timer_num);
|
||||
return ret;
|
||||
}
|
||||
|
@ -174,7 +177,8 @@ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc
|
|||
if(speed_mode == LEDC_HIGH_SPEED_MODE) {
|
||||
gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
|
||||
} else {
|
||||
|
||||
ESP_LOGE(LEDC_TAG, "low speed mode is not implemented");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -191,6 +195,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
|
|||
LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
|
||||
LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
esp_err_t ret = ESP_OK;
|
||||
/*set channel parameters*/
|
||||
/* channel parameters decide how the waveform looks like in one period*/
|
||||
|
|
278
components/driver/pcnt.c
Normal file
278
components/driver/pcnt.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
// 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.
|
||||
#include "esp_log.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#define PCNT_CHANNEL_ERR_STR "PCNT CHANNEL ERROR"
|
||||
#define PCNT_UNIT_ERR_STR "PCNT UNIT ERROR"
|
||||
#define PCNT_GPIO_ERR_STR "PCNT GPIO NUM ERROR"
|
||||
#define PCNT_ADDRESS_ERR_STR "PCNT ADDRESS ERROR"
|
||||
#define PCNT_PARAM_ERR_STR "PCNT PARAM ERROR"
|
||||
#define PCNT_COUNT_MODE_ERR_STR "PCNT COUNTER MODE ERROR"
|
||||
#define PCNT_CTRL_MODE_ERR_STR "PCNT CTRL MODE ERROR"
|
||||
#define PCNT_EVT_TYPE_ERR_STR "PCNT value type error"
|
||||
#define PCNT_CHECK(a,str,ret_val) if(!(a)) { \
|
||||
ESP_LOGE(PCNT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
|
||||
static const char* PCNT_TAG = "PCNT";
|
||||
static portMUX_TYPE pcnt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
#define PCNT_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux)
|
||||
#define PCNT_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux)
|
||||
#define PCNT_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux)
|
||||
#define PCNT_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux)
|
||||
|
||||
esp_err_t pcnt_unit_config(pcnt_config_t *pcnt_config)
|
||||
{
|
||||
uint8_t unit = pcnt_config->channel;
|
||||
uint8_t channel = pcnt_config->unit;
|
||||
int input_io = pcnt_config->pulse_gpio_num;
|
||||
int ctrl_io = pcnt_config->ctrl_gpio_num;
|
||||
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(input_io < 0 || (GPIO_IS_VALID_GPIO(input_io) && (input_io != ctrl_io)), "PCNT pluse input io error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(ctrl_io < 0 || GPIO_IS_VALID_GPIO(ctrl_io), "PCNT ctrl io error", ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((pcnt_config->pos_mode < PCNT_COUNT_MAX) && (pcnt_config->neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((pcnt_config->hctrl_mode < PCNT_MODE_MAX) && (pcnt_config->lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
/*Enalbe hardware module*/
|
||||
periph_module_enable(PERIPH_PCNT_MODULE);
|
||||
/*Set counter range*/
|
||||
pcnt_set_event_value(unit, PCNT_EVT_H_LIM, pcnt_config->counter_h_lim);
|
||||
pcnt_set_event_value(unit, PCNT_EVT_L_LIM, pcnt_config->counter_l_lim);
|
||||
/*Default value after reboot is positive, we disable these events like others*/
|
||||
pcnt_event_disable(unit, PCNT_EVT_H_LIM);
|
||||
pcnt_event_disable(unit, PCNT_EVT_L_LIM);
|
||||
pcnt_event_disable(unit, PCNT_EVT_ZERO);
|
||||
pcnt_filter_disable(unit);
|
||||
/*set pulse input and control mode*/
|
||||
pcnt_set_mode(unit, channel, pcnt_config->pos_mode, pcnt_config->neg_mode, pcnt_config->hctrl_mode, pcnt_config->lctrl_mode);
|
||||
/*Set pulse input and control pins*/
|
||||
pcnt_set_pin(unit, channel, input_io, ctrl_io);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((pos_mode < PCNT_COUNT_MAX) && (neg_mode < PCNT_COUNT_MAX), PCNT_COUNT_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK((hctrl_mode < PCNT_MODE_MAX) && (lctrl_mode < PCNT_MODE_MAX), PCNT_CTRL_MODE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
if(channel == 0) {
|
||||
PCNT.conf_unit[unit].conf0.ch0_pos_mode = pos_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch0_neg_mode = neg_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch0_hctrl_mode = hctrl_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch0_lctrl_mode = lctrl_mode;
|
||||
} else {
|
||||
PCNT.conf_unit[unit].conf0.ch1_pos_mode = pos_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch1_neg_mode = neg_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch1_hctrl_mode = hctrl_mode;
|
||||
PCNT.conf_unit[unit].conf0.ch1_lctrl_mode = lctrl_mode;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_set_pin(pcnt_unit_t unit, pcnt_channel_t channel, int pulse_io, int ctrl_io)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(channel < PCNT_CHANNEL_MAX, PCNT_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(GPIO_IS_VALID_GPIO(pulse_io) || pulse_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(GPIO_IS_VALID_GPIO(ctrl_io) || ctrl_io < 0, PCNT_GPIO_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
int input_sig_index = (channel == 0 ? PCNT_SIG_CH0_IN0_IDX + 4 * unit : PCNT_SIG_CH1_IN0_IDX + 4 * unit);
|
||||
int ctrl_sig_index = (channel == 0 ? PCNT_CTRL_CH0_IN0_IDX + 4 * unit : PCNT_CTRL_CH1_IN0_IDX + 4 * unit);
|
||||
if(pulse_io >= 0) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pulse_io], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(pulse_io, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(pulse_io, GPIO_PULLUP_ONLY);
|
||||
gpio_matrix_in(pulse_io, input_sig_index, 0);
|
||||
}
|
||||
if(ctrl_io >= 0) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[ctrl_io], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(ctrl_io, GPIO_MODE_INPUT);
|
||||
gpio_set_pull_mode(ctrl_io, GPIO_PULLUP_ONLY);
|
||||
gpio_matrix_in(ctrl_io, ctrl_sig_index, 0);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_get_counter_value(pcnt_unit_t pcnt_unit, int16_t* count)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(count != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
*count = (int16_t) PCNT.cnt_unit[pcnt_unit].cnt_val;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_counter_pause(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
PCNT.ctrl.val |= BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2));
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_counter_resume(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
PCNT.ctrl.val &= (~(BIT(PCNT_CNT_PAUSE_U0_S + (pcnt_unit * 2))));
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_counter_clear(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
PCNT.ctrl.val &= (~(BIT(PCNT_PLUS_CNT_RST_U0_S + (pcnt_unit * 2))));
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_intr_enable(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
PCNT.int_ena.val |= BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit);
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_intr_disable(pcnt_unit_t pcnt_unit)
|
||||
{
|
||||
PCNT_CHECK(pcnt_unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_ENTER_CRITICAL(&pcnt_spinlock);
|
||||
PCNT.int_ena.val &= (~(BIT(PCNT_CNT_THR_EVENT_U0_INT_ENA_S + pcnt_unit)));
|
||||
PCNT_EXIT_CRITICAL(&pcnt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_event_enable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(evt_type == PCNT_EVT_L_LIM) {
|
||||
PCNT.conf_unit[unit].conf0.thr_l_lim_en = 1;
|
||||
} else if(evt_type == PCNT_EVT_H_LIM) {
|
||||
PCNT.conf_unit[unit].conf0.thr_h_lim_en = 1;
|
||||
} else if(evt_type == PCNT_EVT_THRES_0) {
|
||||
PCNT.conf_unit[unit].conf0.thr_thres0_en = 1;
|
||||
} else if(evt_type == PCNT_EVT_THRES_1) {
|
||||
PCNT.conf_unit[unit].conf0.thr_thres1_en = 1;
|
||||
} else if(evt_type == PCNT_EVT_ZERO) {
|
||||
PCNT.conf_unit[unit].conf0.thr_zero_en = 1;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_event_disable(pcnt_unit_t unit, pcnt_evt_type_t evt_type)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(evt_type == PCNT_EVT_L_LIM) {
|
||||
PCNT.conf_unit[unit].conf0.thr_l_lim_en = 0;
|
||||
} else if(evt_type == PCNT_EVT_H_LIM) {
|
||||
PCNT.conf_unit[unit].conf0.thr_h_lim_en = 0;
|
||||
} else if(evt_type == PCNT_EVT_THRES_0) {
|
||||
PCNT.conf_unit[unit].conf0.thr_thres0_en = 0;
|
||||
} else if(evt_type == PCNT_EVT_THRES_1) {
|
||||
PCNT.conf_unit[unit].conf0.thr_thres1_en = 0;
|
||||
} else if(evt_type == PCNT_EVT_ZERO) {
|
||||
PCNT.conf_unit[unit].conf0.thr_zero_en = 0;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_set_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t value)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(evt_type == PCNT_EVT_L_LIM) {
|
||||
PCNT.conf_unit[unit].conf2.cnt_l_lim = value;
|
||||
} else if(evt_type == PCNT_EVT_H_LIM) {
|
||||
PCNT.conf_unit[unit].conf2.cnt_h_lim = value;
|
||||
} else if(evt_type == PCNT_EVT_THRES_0) {
|
||||
PCNT.conf_unit[unit].conf1.cnt_thres0 = value;
|
||||
} else if(evt_type == PCNT_EVT_THRES_1) {
|
||||
PCNT.conf_unit[unit].conf1.cnt_thres1 = value;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_get_event_value(pcnt_unit_t unit, pcnt_evt_type_t evt_type, int16_t *value)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(evt_type < PCNT_EVT_MAX, PCNT_EVT_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(value != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
if(evt_type == PCNT_EVT_L_LIM) {
|
||||
*value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_l_lim;
|
||||
} else if(evt_type == PCNT_EVT_H_LIM) {
|
||||
*value = (int16_t) PCNT.conf_unit[unit].conf2.cnt_h_lim;
|
||||
} else if(evt_type == PCNT_EVT_THRES_0) {
|
||||
*value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres0;
|
||||
} else if(evt_type == PCNT_EVT_THRES_1) {
|
||||
*value = (int16_t) PCNT.conf_unit[unit].conf1.cnt_thres1;
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_set_filter_value(pcnt_unit_t unit, uint16_t filter_val)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(filter_val < 1024, PCNT_PARAM_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT.conf_unit[unit].conf0.filter_thres = filter_val;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_get_filter_value(pcnt_unit_t unit, uint16_t *filter_val)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT_CHECK(filter_val != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
*filter_val = PCNT.conf_unit[unit].conf0.filter_thres;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_filter_enable(pcnt_unit_t unit)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT.conf_unit[unit].conf0.filter_en = 1;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_filter_disable(pcnt_unit_t unit)
|
||||
{
|
||||
PCNT_CHECK(unit < PCNT_UNIT_MAX, PCNT_UNIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
PCNT.conf_unit[unit].conf0.filter_en = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_isr_register(uint32_t pcnt_intr_num, void (*fun)(void*), void * arg)
|
||||
{
|
||||
PCNT_CHECK(fun != NULL, PCNT_ADDRESS_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
ESP_INTR_DISABLE(pcnt_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_PCNT_INTR_SOURCE, pcnt_intr_num);
|
||||
xt_set_interrupt_handler(pcnt_intr_num, fun, arg);
|
||||
ESP_INTR_ENABLE(pcnt_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
|
@ -25,6 +25,10 @@ void periph_module_enable(periph_module_t periph)
|
|||
{
|
||||
portENTER_CRITICAL(&periph_spinlock);
|
||||
switch(periph) {
|
||||
case PERIPH_RMT_MODULE:
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
|
||||
break;
|
||||
case PERIPH_LEDC_MODULE:
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
|
||||
|
@ -89,6 +93,10 @@ void periph_module_enable(periph_module_t periph)
|
|||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
|
||||
break;
|
||||
case PERIPH_PCNT_MODULE:
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -99,6 +107,10 @@ void periph_module_disable(periph_module_t periph)
|
|||
{
|
||||
portENTER_CRITICAL(&periph_spinlock);
|
||||
switch(periph) {
|
||||
case PERIPH_RMT_MODULE:
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST);
|
||||
break;
|
||||
case PERIPH_LEDC_MODULE:
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
|
||||
|
@ -163,6 +175,10 @@ void periph_module_disable(periph_module_t periph)
|
|||
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
|
||||
break;
|
||||
case PERIPH_PCNT_MODULE:
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
717
components/driver/rmt.c
Normal file
717
components/driver/rmt.c
Normal file
|
@ -0,0 +1,717 @@
|
|||
// 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.
|
||||
#include <esp_types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "esp_intr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "driver/rmt.h"
|
||||
|
||||
#define RMT_SOUCCE_CLK_APB (APB_CLK_FREQ) /*!< RMT source clock is APB_CLK */
|
||||
#define RMT_SOURCE_CLK_REF (1 * 1000000) /*!< not used yet */
|
||||
#define RMT_SOURCE_CLK(select) ((select == RMT_BASECLK_REF) ? (RMT_SOURCE_CLK_REF) : (RMT_SOUCCE_CLK_APB)) /*! RMT source clock frequency */
|
||||
|
||||
#define RMT_CHANNEL_ERROR_STR "RMT CHANNEL ERR"
|
||||
#define RMT_ADDR_ERROR_STR "RMT ADDRESS ERR"
|
||||
#define RMT_MEM_CNT_ERROR_STR "RMT MEM BLOCK NUM ERR"
|
||||
#define RMT_CARRIER_ERROR_STR "RMT CARRIER LEVEL ERR"
|
||||
#define RMT_MEM_OWNER_ERROR_STR "RMT MEM OWNER_ERR"
|
||||
#define RMT_BASECLK_ERROR_STR "RMT BASECLK ERR"
|
||||
#define RMT_WR_MEM_OVF_ERROR_STR "RMT WR MEM OVERFLOW"
|
||||
#define RMT_GPIO_ERROR_STR "RMT GPIO ERROR"
|
||||
#define RMT_MODE_ERROR_STR "RMT MODE ERROR"
|
||||
#define RMT_CLK_DIV_ERROR_STR "RMT CLK DIV ERR"
|
||||
#define RMT_DRIVER_ERROR_STR "RMT DRIVER ERR"
|
||||
#define RMT_DRIVER_LENGTH_ERROR_STR "RMT PARAM LEN ERROR"
|
||||
|
||||
static const char* RMT_TAG = "RMT";
|
||||
static bool s_rmt_driver_installed = false;
|
||||
|
||||
#define RMT_CHECK(a, str, ret) if (!(a)) { \
|
||||
ESP_LOGE(RMT_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret); \
|
||||
}
|
||||
static portMUX_TYPE rmt_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
typedef struct {
|
||||
int tx_offset;
|
||||
int tx_len_rem;
|
||||
int tx_sub_len;
|
||||
rmt_channel_t channel;
|
||||
rmt_item32_t* tx_data;
|
||||
xSemaphoreHandle tx_sem;
|
||||
RingbufHandle_t tx_buf;
|
||||
RingbufHandle_t rx_buf;
|
||||
} rmt_obj_t;
|
||||
|
||||
rmt_obj_t* p_rmt_obj[RMT_CHANNEL_MAX] = {0};
|
||||
|
||||
static void rmt_set_tx_wrap_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.mem_tx_wrap_en = en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
static void rmt_set_data_mode(rmt_data_mode_t data_mode)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.fifo_mask = data_mode;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_clk_div(rmt_channel_t channel, uint8_t div_cnt)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.div_cnt = div_cnt;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_clk_div(rmt_channel_t channel, uint8_t* div_cnt)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(div_cnt != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*div_cnt = RMT.conf_ch[channel].conf0.div_cnt;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_idle_thresh(rmt_channel_t channel, uint16_t thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.idle_thres = thresh;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(thresh != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*thresh = RMT.conf_ch[channel].conf0.idle_thres;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_mem_block_num(rmt_channel_t channel, uint8_t rmt_mem_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(rmt_mem_num < 16, RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.mem_size = rmt_mem_num;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(rmt_mem_num != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*rmt_mem_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(carrier_level < RMT_CARRIER_LEVEL_MAX, RMT_CARRIER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.carrier_duty_ch[channel].high = high_level;
|
||||
RMT.carrier_duty_ch[channel].low = low_level;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT.conf_ch[channel].conf0.mem_pd = pd_en;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool* pd_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*pd_en = (bool) RMT.conf_ch[channel].conf0.mem_pd;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_tx_start(rmt_channel_t channel, bool tx_idx_rst)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
if(tx_idx_rst) {
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
RMT.conf_ch[channel].conf1.tx_start = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_tx_stop(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_start = 0;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_rx_start(rmt_channel_t channel, bool rx_idx_rst)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
if(rx_idx_rst) {
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_rx_stop(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_memory_rw_rst(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_memory_owner(rmt_channel_t channel, rmt_mem_owner_t owner)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(owner < RMT_MEM_OWNER_MAX, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_owner = owner;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(owner != NULL, RMT_MEM_OWNER_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*owner = (rmt_mem_owner_t) RMT.conf_ch[channel].conf1.mem_owner;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_tx_loop_mode(rmt_channel_t channel, bool loop_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = loop_en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool* loop_en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*loop_en = (bool) RMT.conf_ch[channel].conf1.tx_conti_mode;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = rx_filter_en;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = thresh;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(base_clk < RMT_BASECLK_MAX, RMT_BASECLK_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = base_clk;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t* src_clk)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*src_clk = (rmt_source_clk_t) (RMT.conf_ch[channel].conf1.ref_always_on);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_idle_level(rmt_channel_t channel, bool idle_out_en, rmt_idle_level_t level)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(level < RMT_IDLE_LEVEL_MAX, "RMT IDLE LEVEL ERR", ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = idle_out_en;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = level;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_status(rmt_channel_t channel, uint32_t* status)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*status = RMT.status_ch[channel];
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
rmt_data_mode_t rmt_get_data_mode()
|
||||
{
|
||||
return (rmt_data_mode_t) (RMT.apb_conf.fifo_mask);
|
||||
}
|
||||
|
||||
void rmt_set_intr_enable_mask(uint32_t mask)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.int_ena.val |= mask;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
void rmt_clr_intr_enable_mask(uint32_t mask)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.int_ena.val &= (~mask);
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_rx_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3 + 1));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3 + 1));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_err_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3 + 2));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3 + 2));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
rmt_set_intr_enable_mask(BIT(channel * 3));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel * 3));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_evt_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(evt_thresh < 256, "RMT EVT THRESH ERR", ESP_ERR_INVALID_ARG);
|
||||
if(en) {
|
||||
RMT.tx_lim_ch[channel].limit = evt_thresh;
|
||||
rmt_set_tx_wrap_en(channel, true);
|
||||
rmt_set_intr_enable_mask(BIT(channel + 24));
|
||||
} else {
|
||||
rmt_clr_intr_enable_mask(BIT(channel + 24));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(mode < RMT_MODE_MAX, RMT_MODE_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(((GPIO_IS_VALID_GPIO(gpio_num) && (mode == RMT_MODE_RX)) || (GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) && (mode == RMT_MODE_TX))),
|
||||
RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], 2);
|
||||
if(mode == RMT_MODE_TX) {
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
|
||||
gpio_matrix_out(gpio_num, RMT_SIG_OUT0_IDX + channel, 0, 0);
|
||||
} else {
|
||||
gpio_set_direction(gpio_num, GPIO_MODE_INPUT);
|
||||
gpio_matrix_in(gpio_num, RMT_SIG_IN0_IDX + channel, 0);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_config(rmt_config_t* rmt_param)
|
||||
{
|
||||
uint8_t mode = rmt_param->rmt_mode;
|
||||
uint8_t channel = rmt_param->channel;
|
||||
uint8_t gpio_num = rmt_param->gpio_num;
|
||||
uint8_t mem_cnt = rmt_param->mem_block_num;
|
||||
int clk_div = rmt_param->clk_div;
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(GPIO_IS_VALID_GPIO(gpio_num), RMT_GPIO_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((mem_cnt + channel <= 8 && mem_cnt > 0), RMT_MEM_CNT_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((clk_div > 0), RMT_CLK_DIV_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
periph_module_enable(PERIPH_RMT_MODULE);
|
||||
|
||||
RMT.conf_ch[channel].conf0.div_cnt = clk_div;
|
||||
/*Visit data use memory not FIFO*/
|
||||
rmt_set_data_mode(RMT_DATA_MODE_MEM);
|
||||
/*Reset tx/rx memory index */
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
if(mode == RMT_MODE_TX) {
|
||||
uint32_t rmt_source_clk_hz = 0;
|
||||
uint32_t carrier_freq_hz = rmt_param->tx_config.carrier_freq_hz;
|
||||
uint16_t carrier_duty_percent = rmt_param->tx_config.carrier_duty_percent;
|
||||
uint8_t carrier_level = rmt_param->tx_config.carrier_level;
|
||||
uint8_t idle_level = rmt_param->tx_config.idle_level;
|
||||
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = rmt_param->tx_config.loop_en;
|
||||
/*Memory set block number*/
|
||||
RMT.conf_ch[channel].conf0.mem_size = mem_cnt;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
/*We use APB clock in this version, which is 80Mhz, later we will release system reference clock*/
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB;
|
||||
rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB);
|
||||
/*Set idle level */
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = rmt_param->tx_config.idle_output_en;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = idle_level;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
/*Set carrier*/
|
||||
uint32_t duty_div, duty_h, duty_l;
|
||||
duty_div = rmt_source_clk_hz / carrier_freq_hz;
|
||||
duty_h = duty_div * carrier_duty_percent / 100;
|
||||
duty_l = duty_div - duty_h;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
RMT.carrier_duty_ch[channel].high = duty_h;
|
||||
RMT.carrier_duty_ch[channel].low = duty_l;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = rmt_param->tx_config.carrier_en;
|
||||
ESP_LOGD(RMT_TAG, "Rmt Tx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Carrier_Hz %u|Duty %u",
|
||||
channel, gpio_num, rmt_source_clk_hz, clk_div, carrier_freq_hz, carrier_duty_percent);
|
||||
}
|
||||
else if(RMT_MODE_RX == mode) {
|
||||
uint8_t filter_cnt = rmt_param->rx_config.filter_ticks_thresh;
|
||||
uint16_t threshold = rmt_param->rx_config.idle_threshold;
|
||||
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
/*clock init*/
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = RMT_BASECLK_APB;
|
||||
uint32_t rmt_source_clk_hz = RMT_SOURCE_CLK(RMT_BASECLK_APB);
|
||||
/*memory set block number and owner*/
|
||||
RMT.conf_ch[channel].conf0.mem_size = mem_cnt;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
/*Set idle threshold*/
|
||||
RMT.conf_ch[channel].conf0.idle_thres = threshold;
|
||||
/* Set RX filter */
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = filter_cnt;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = rmt_param->rx_config.filter_en;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
|
||||
ESP_LOGD(RMT_TAG, "Rmt Rx Channel %u|Gpio %u|Sclk_Hz %u|Div %u|Thresold %u|Filter %u",
|
||||
channel, gpio_num, rmt_source_clk_hz, clk_div, threshold, filter_cnt);
|
||||
}
|
||||
rmt_set_pin(channel, mode, gpio_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR rmt_fill_memory(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset)
|
||||
{
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
RMT.apb_conf.fifo_mask = RMT_DATA_MODE_MEM;
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
int i;
|
||||
for(i = 0; i < item_num; i++) {
|
||||
RMTMEM.chan[channel].data32[i + mem_offset].val = item[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t item_num, uint16_t mem_offset)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, (0));
|
||||
RMT_CHECK((item != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK((item_num > 0), RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
/*Each block has 64 x 32 bits of data*/
|
||||
uint8_t mem_cnt = RMT.conf_ch[channel].conf0.mem_size;
|
||||
RMT_CHECK((mem_cnt * RMT_MEM_ITEM_NUM >= item_num), RMT_WR_MEM_OVF_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
rmt_fill_memory(channel, item, item_num, mem_offset);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_isr_register(uint8_t rmt_intr_num, void (*fn)(void*), void * arg)
|
||||
{
|
||||
RMT_CHECK((fn != NULL), RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(s_rmt_driver_installed == false, "RMT DRIVER INSTALLED, CAN NOT REG ISR HANDLER", ESP_FAIL);
|
||||
portENTER_CRITICAL(&rmt_spinlock);
|
||||
ESP_INTR_DISABLE(rmt_intr_num);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, rmt_intr_num);
|
||||
xt_set_interrupt_handler(rmt_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(rmt_intr_num);
|
||||
portEXIT_CRITICAL(&rmt_spinlock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int IRAM_ATTR rmt_get_mem_len(rmt_channel_t channel)
|
||||
{
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * RMT_MEM_ITEM_NUM;
|
||||
volatile rmt_item32_t* data = RMTMEM.chan[channel].data32;
|
||||
int idx;
|
||||
for(idx = 0; idx < item_block_len; idx++) {
|
||||
if(data[idx].duration0 == 0) {
|
||||
return idx;
|
||||
} else if(data[idx].duration1 == 0) {
|
||||
return idx + 1;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR rmt_driver_isr_default(void* arg)
|
||||
{
|
||||
uint32_t intr_st = RMT.int_st.val;
|
||||
uint32_t i = 0;
|
||||
uint8_t channel;
|
||||
portBASE_TYPE HPTaskAwoken = 0;
|
||||
for(i = 0; i < 32; i++) {
|
||||
if(i < 24) {
|
||||
if(intr_st & (BIT(i))) {
|
||||
channel = i / 3;
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
switch(i % 3) {
|
||||
//TX END
|
||||
case 0:
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : TX END\n");
|
||||
xSemaphoreGiveFromISR(p_rmt->tx_sem, &HPTaskAwoken);
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
p_rmt->tx_data = NULL;
|
||||
p_rmt->tx_len_rem = 0;
|
||||
p_rmt->tx_offset = 0;
|
||||
p_rmt->tx_sub_len = 0;
|
||||
break;
|
||||
//RX_END
|
||||
case 1:
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT INTR : RX END");
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
int item_len = rmt_get_mem_len(channel);
|
||||
//change memory owner to protect data.
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_TX;
|
||||
if(p_rmt->rx_buf) {
|
||||
BaseType_t res = xRingbufferSendFromISR(p_rmt->rx_buf, (void*) RMTMEM.chan[channel].data32, item_len * 4, &HPTaskAwoken);
|
||||
if(res == pdFALSE) {
|
||||
ESP_LOGE(RMT_TAG, "RMT RX BUFFER FULL");
|
||||
} else {
|
||||
|
||||
}
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
} else {
|
||||
ESP_EARLY_LOGE(RMT_TAG, "RMT RX BUFFER ERROR\n");
|
||||
}
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = RMT_MEM_OWNER_RX;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
break;
|
||||
//ERR
|
||||
case 2:
|
||||
ESP_EARLY_LOGE(RMT_TAG, "RMT[%d] ERR", channel);
|
||||
ESP_EARLY_LOGE(RMT_TAG, "status: 0x%08x", RMT.status_ch[channel]);
|
||||
RMT.int_ena.val &= (~(BIT(i)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
RMT.int_clr.val = BIT(i);
|
||||
}
|
||||
} else {
|
||||
if(intr_st & (BIT(i))) {
|
||||
channel = i - 24;
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
RMT.int_clr.val = BIT(i);
|
||||
ESP_EARLY_LOGD(RMT_TAG, "RMT CH[%d]: EVT INTR", channel);
|
||||
if(p_rmt->tx_data == NULL) {
|
||||
//skip
|
||||
} else {
|
||||
rmt_item32_t* pdata = p_rmt->tx_data;
|
||||
int len_rem = p_rmt->tx_len_rem;
|
||||
if(len_rem >= p_rmt->tx_sub_len) {
|
||||
rmt_fill_memory(channel, pdata, p_rmt->tx_sub_len, p_rmt->tx_offset);
|
||||
p_rmt->tx_data += p_rmt->tx_sub_len;
|
||||
p_rmt->tx_len_rem -= p_rmt->tx_sub_len;
|
||||
} else if(len_rem == 0) {
|
||||
RMTMEM.chan[channel].data32[p_rmt->tx_offset].val = 0;
|
||||
} else {
|
||||
rmt_fill_memory(channel, pdata, len_rem, p_rmt->tx_offset);
|
||||
RMTMEM.chan[channel].data32[p_rmt->tx_offset + len_rem].val = 0;
|
||||
p_rmt->tx_data += len_rem;
|
||||
p_rmt->tx_len_rem -= len_rem;
|
||||
}
|
||||
if(p_rmt->tx_offset == 0) {
|
||||
p_rmt->tx_offset = p_rmt->tx_sub_len;
|
||||
} else {
|
||||
p_rmt->tx_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rmt_driver_uninstall(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(p_rmt_obj[channel] == NULL) {
|
||||
return ESP_OK;
|
||||
}
|
||||
xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY);
|
||||
rmt_set_rx_intr_en(channel, 0);
|
||||
rmt_set_err_intr_en(channel, 0);
|
||||
rmt_set_tx_intr_en(channel, 0);
|
||||
rmt_set_evt_intr_en(channel, 0, 0xffff);
|
||||
if(p_rmt_obj[channel]->tx_sem) {
|
||||
vSemaphoreDelete(p_rmt_obj[channel]->tx_sem);
|
||||
p_rmt_obj[channel]->tx_sem = NULL;
|
||||
}
|
||||
if(p_rmt_obj[channel]->rx_buf) {
|
||||
vRingbufferDelete(p_rmt_obj[channel]->rx_buf);
|
||||
p_rmt_obj[channel]->rx_buf = NULL;
|
||||
}
|
||||
free(p_rmt_obj[channel]);
|
||||
p_rmt_obj[channel] = NULL;
|
||||
s_rmt_driver_installed = false;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
if(p_rmt_obj[channel] != NULL) {
|
||||
ESP_LOGD(RMT_TAG, "RMT DRIVER ALREADY INSTALLED");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_INTR_DISABLE(rmt_intr_num);
|
||||
p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t));
|
||||
|
||||
if(p_rmt_obj[channel] == NULL) {
|
||||
ESP_LOGE(RMT_TAG, "RMT driver malloc error");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
memset(p_rmt_obj[channel], 0, sizeof(rmt_obj_t));
|
||||
|
||||
p_rmt_obj[channel]->tx_len_rem = 0;
|
||||
p_rmt_obj[channel]->tx_data = NULL;
|
||||
p_rmt_obj[channel]->channel = channel;
|
||||
p_rmt_obj[channel]->tx_offset = 0;
|
||||
p_rmt_obj[channel]->tx_sub_len = 0;
|
||||
|
||||
if(p_rmt_obj[channel]->tx_sem == NULL) {
|
||||
p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(p_rmt_obj[channel]->tx_sem);
|
||||
}
|
||||
if(p_rmt_obj[channel]->rx_buf == NULL && rx_buf_size > 0) {
|
||||
p_rmt_obj[channel]->rx_buf = xRingbufferCreate(rx_buf_size, RINGBUF_TYPE_NOSPLIT);
|
||||
rmt_set_rx_intr_en(channel, 1);
|
||||
rmt_set_err_intr_en(channel, 1);
|
||||
}
|
||||
if(s_rmt_driver_installed == false) {
|
||||
rmt_isr_register(rmt_intr_num, rmt_driver_isr_default, NULL);
|
||||
s_rmt_driver_installed = true;
|
||||
}
|
||||
rmt_set_tx_intr_en(channel, 1);
|
||||
ESP_INTR_ENABLE(rmt_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_write_items(rmt_channel_t channel, rmt_item32_t* rmt_item, int item_num, bool wait_tx_done)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(rmt_item != NULL, RMT_ADDR_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(item_num > 0, RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
rmt_obj_t* p_rmt = p_rmt_obj[channel];
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * RMT_MEM_ITEM_NUM;
|
||||
int item_sub_len = block_num * RMT_MEM_ITEM_NUM / 2;
|
||||
int len_rem = item_num;
|
||||
xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
|
||||
// fill the memory block first
|
||||
if(item_num >= item_block_len) {
|
||||
rmt_fill_memory(channel, rmt_item, item_block_len, 0);
|
||||
RMT.tx_lim_ch[channel].limit = item_sub_len;
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1;
|
||||
len_rem -= item_block_len;
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
|
||||
rmt_set_evt_intr_en(channel, 1, item_sub_len);
|
||||
p_rmt->tx_data = rmt_item + item_block_len;
|
||||
p_rmt->tx_len_rem = len_rem;
|
||||
p_rmt->tx_offset = 0;
|
||||
p_rmt->tx_sub_len = item_sub_len;
|
||||
} else {
|
||||
rmt_fill_memory(channel, rmt_item, len_rem, 0);
|
||||
RMTMEM.chan[channel].data32[len_rem].val = 0;
|
||||
len_rem = 0;
|
||||
}
|
||||
rmt_tx_start(channel, true);
|
||||
if(wait_tx_done) {
|
||||
xSemaphoreTake(p_rmt->tx_sem, portMAX_DELAY);
|
||||
xSemaphoreGive(p_rmt->tx_sem);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_wait_tx_done(rmt_channel_t channel)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
xSemaphoreTake(p_rmt_obj[channel]->tx_sem, portMAX_DELAY);
|
||||
xSemaphoreGive(p_rmt_obj[channel]->tx_sem);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t rmt_get_ringbuf_handler(rmt_channel_t channel, RingbufHandle_t* buf_handler)
|
||||
{
|
||||
RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL);
|
||||
RMT_CHECK(buf_handler != NULL, RMT_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
*buf_handler = p_rmt_obj[channel]->rx_buf;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
275
components/driver/timer.c
Normal file
275
components/driver/timer.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
// 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.
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "driver/timer.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
static const char* TIMER_TAG = "TIMER_GROUP";
|
||||
#define TIMER_CHECK(a, str, ret_val) if (!(a)) { \
|
||||
ESP_LOGE(TIMER_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
|
||||
return (ret_val); \
|
||||
}
|
||||
#define TIMER_GROUP_NUM_ERROR "TIMER GROUP NUM ERROR"
|
||||
#define TIMER_NUM_ERROR "HW TIMER NUM ERROR"
|
||||
#define TIMER_PARAM_ADDR_ERROR "HW TIMER PARAM ADDR ERROR"
|
||||
#define TIMER_COUNT_DIR_ERROR "HW TIMER COUNTER DIR ERROR"
|
||||
#define TIMER_AUTORELOAD_ERROR "HW TIMER AUTORELOAD ERROR"
|
||||
#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"
|
||||
#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"
|
||||
static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
|
||||
static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
|
||||
|
||||
#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux);
|
||||
#define TIMER_EXIT_CRITICAL(mux) portEXIT_CRITICAL(mux);
|
||||
|
||||
esp_err_t timer_get_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* timer_val)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_val != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].update = 1;
|
||||
*timer_val = ((uint64_t) TG[group_num]->hw_timer[timer_num].cnt_high << 32)
|
||||
| (TG[group_num]->hw_timer[timer_num].cnt_low);
|
||||
portEXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_get_counter_time_sec(timer_group_t group_num, timer_idx_t timer_num, double* time)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(time != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
uint64_t timer_val;
|
||||
esp_err_t err = timer_get_counter_value(group_num, timer_num, &timer_val);
|
||||
if (err == ESP_OK) {
|
||||
uint16_t div = TG[group_num]->hw_timer[timer_num].config.divider;
|
||||
*time = (double)timer_val * div / TIMER_BASE_CLK;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_counter_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t load_val)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].load_high = (uint32_t) (load_val >> 32);
|
||||
TG[group_num]->hw_timer[timer_num].load_low = (uint32_t) load_val;
|
||||
TG[group_num]->hw_timer[timer_num].reload = 1;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_start(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.enable = 1;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_pause(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.enable = 0;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_counter_mode(timer_group_t group_num, timer_idx_t timer_num, timer_count_dir_t counter_dir)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(counter_dir < TIMER_COUNT_MAX, TIMER_COUNT_DIR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.increase = counter_dir;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_auto_reload(timer_group_t group_num, timer_idx_t timer_num, timer_autoreload_t reload)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(reload < TIMER_AUTORELOAD_MAX, TIMER_AUTORELOAD_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.autoreload = reload;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_divider(timer_group_t group_num, timer_idx_t timer_num, uint16_t divider)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
int timer_en = TG[group_num]->hw_timer[timer_num].config.enable;
|
||||
TG[group_num]->hw_timer[timer_num].config.enable = 0;
|
||||
TG[group_num]->hw_timer[timer_num].config.divider = divider;
|
||||
TG[group_num]->hw_timer[timer_num].config.enable = timer_en;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_value)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
|
||||
TG[group_num]->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_get_alarm_value(timer_group_t group_num, timer_idx_t timer_num, uint64_t* alarm_value)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(alarm_value != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
*alarm_value = ((uint64_t) TG[group_num]->hw_timer[timer_num].alarm_high << 32)
|
||||
| (TG[group_num]->hw_timer[timer_num].alarm_low);
|
||||
portEXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_set_alarm(timer_group_t group_num, timer_idx_t timer_num, timer_alarm_t alarm_en)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(alarm_en < TIMER_ALARM_MAX, TIMER_ALARM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.alarm_en = alarm_en;
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_isr_register(timer_group_t group_num, timer_idx_t timer_num, int timer_intr_num,
|
||||
timer_intr_mode_t intr_type, void (*fn)(void*), void * arg)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(fn != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
ESP_INTR_DISABLE(timer_intr_num);
|
||||
int intr_source = 0;
|
||||
switch(group_num) {
|
||||
case TIMER_GROUP_0:
|
||||
default:
|
||||
if(intr_type == TIMER_INTR_LEVEL) {
|
||||
intr_source = ETS_TG0_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||
} else {
|
||||
intr_source = ETS_TG0_T0_EDGE_INTR_SOURCE + timer_num;
|
||||
}
|
||||
break;
|
||||
case TIMER_GROUP_1:
|
||||
if(intr_type == TIMER_INTR_LEVEL) {
|
||||
intr_source = ETS_TG1_T0_LEVEL_INTR_SOURCE + timer_num;
|
||||
} else {
|
||||
intr_source = ETS_TG1_T0_EDGE_INTR_SOURCE + timer_num;
|
||||
}
|
||||
break;
|
||||
}
|
||||
intr_matrix_set(xPortGetCoreID(), intr_source, timer_intr_num);
|
||||
xt_set_interrupt_handler(timer_intr_num, fn, arg);
|
||||
ESP_INTR_ENABLE(timer_intr_num);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_init(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
if(group_num == 0) {
|
||||
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||
} else if(group_num == 1) {
|
||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||
}
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->hw_timer[timer_num].config.autoreload = config->auto_reload;
|
||||
TG[group_num]->hw_timer[timer_num].config.divider = config->divider;
|
||||
TG[group_num]->hw_timer[timer_num].config.enable = config->counter_en;
|
||||
TG[group_num]->hw_timer[timer_num].config.increase = config->counter_dir;
|
||||
TG[group_num]->hw_timer[timer_num].config.alarm_en = config->alarm_en;
|
||||
TG[group_num]->hw_timer[timer_num].config.level_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 1 : 0);
|
||||
TG[group_num]->hw_timer[timer_num].config.edge_int_en = (config->intr_type == TIMER_INTR_LEVEL ? 0 : 1);
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer_config_t *config)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(config != NULL, TIMER_PARAM_ADDR_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_ENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
config->alarm_en = TG[group_num]->hw_timer[timer_num].config.alarm_en;
|
||||
config->auto_reload = TG[group_num]->hw_timer[timer_num].config.autoreload;
|
||||
config->counter_dir = TG[group_num]->hw_timer[timer_num].config.increase;
|
||||
config->counter_dir = TG[group_num]->hw_timer[timer_num].config.divider;
|
||||
config->counter_en = TG[group_num]->hw_timer[timer_num].config.enable;
|
||||
if(TG[group_num]->hw_timer[timer_num].config.level_int_en) {
|
||||
config->intr_type =TIMER_INTR_LEVEL;
|
||||
}
|
||||
TIMER_EXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->int_ena.val |= en_mask;
|
||||
portEXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
TG[group_num]->int_ena.val &= (~disable_mask);
|
||||
portEXIT_CRITICAL(&timer_spinlock[group_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
return timer_group_intr_enable(group_num, BIT(timer_num));
|
||||
}
|
||||
|
||||
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
return timer_group_intr_disable(group_num, BIT(timer_num));
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,8 @@ typedef struct {
|
|||
|
||||
|
||||
static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};
|
||||
static uart_dev_t* UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};
|
||||
/* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */
|
||||
static DRAM_ATTR uart_dev_t* const UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};
|
||||
static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
|
||||
|
||||
esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit)
|
||||
|
|
|
@ -16,25 +16,8 @@
|
|||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
typedef enum{
|
||||
XTAL_40M = 40,
|
||||
XTAL_26M = 26,
|
||||
XTAL_24M = 24,
|
||||
XTAL_AUTO = 0
|
||||
} xtal_freq_t;
|
||||
|
||||
typedef enum{
|
||||
CPU_80M = 1,
|
||||
CPU_160M = 2,
|
||||
CPU_240M = 3,
|
||||
} cpu_freq_t;
|
||||
|
||||
extern void phy_get_romfunc_addr();
|
||||
|
||||
// TODO: these functions need to be moved from librtc to ESP-IDF
|
||||
extern void rtc_init_lite();
|
||||
extern void rtc_set_cpu_freq(xtal_freq_t xtal_freq, cpu_freq_t cpu_freq);
|
||||
#include "phy.h"
|
||||
#include "rtc.h"
|
||||
|
||||
/*
|
||||
* This function is not exposed as an API at this point,
|
||||
|
@ -52,7 +35,7 @@ void esp_set_cpu_freq(void)
|
|||
// wait uart tx finish, otherwise some uart output will be lost
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
rtc_init_lite();
|
||||
rtc_init_lite(XTAL_AUTO);
|
||||
cpu_freq_t freq = CPU_80M;
|
||||
switch(freq_mhz) {
|
||||
case 240:
|
||||
|
@ -73,7 +56,7 @@ void esp_set_cpu_freq(void)
|
|||
// wait uart tx finish, otherwise some uart output will be lost
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
rtc_set_cpu_freq(XTAL_AUTO, freq);
|
||||
rtc_set_cpu_freq(freq);
|
||||
ets_update_cpu_frequency(freq_mhz);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,9 +116,7 @@ void IRAM_ATTR call_start_cpu0()
|
|||
//Flush and enable icache for APP CPU
|
||||
Cache_Flush(1);
|
||||
Cache_Read_Enable(1);
|
||||
//Un-stall the app cpu; the panic handler may have stalled it.
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
esp_cpu_unstall(1);
|
||||
//Enable clock gating and reset the app cpu.
|
||||
SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
|
||||
|
@ -154,6 +152,7 @@ void IRAM_ATTR call_start_cpu1()
|
|||
|
||||
void start_cpu0_default(void)
|
||||
{
|
||||
esp_setup_syscall_table();
|
||||
//Enable trace memory and immediately start trace.
|
||||
#if CONFIG_MEMMAP_TRACEMEM
|
||||
#if CONFIG_MEMMAP_TRACEMEM_TWOBANKS
|
||||
|
@ -174,7 +173,6 @@ void start_cpu0_default(void)
|
|||
#if CONFIG_TASK_WDT
|
||||
esp_task_wdt_init();
|
||||
#endif
|
||||
esp_setup_syscall_table();
|
||||
esp_setup_time_syscalls();
|
||||
esp_vfs_dev_uart_register();
|
||||
esp_reent_init(_GLOBAL_REENT);
|
||||
|
|
44
components/esp32/cpu_util.c
Normal file
44
components/esp32/cpu_util.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2013-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.
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void IRAM_ATTR esp_cpu_stall(int cpu_id)
|
||||
{
|
||||
if (cpu_id == 1) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR esp_cpu_unstall(int cpu_id)
|
||||
{
|
||||
if (cpu_id == 1) {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C1_M);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
#include "soc/dport_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_deepsleep.h"
|
||||
#include "rtc.h"
|
||||
|
||||
/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
|
||||
is not thread-safe. */
|
||||
|
@ -46,3 +47,21 @@ void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
|
|||
}
|
||||
|
||||
void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void);
|
||||
|
||||
void esp_deep_sleep(uint64_t time_in_us)
|
||||
{
|
||||
rtc_set_cpu_freq(CPU_XTAL);
|
||||
if (esp_get_deep_sleep_wake_stub() == NULL) {
|
||||
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
|
||||
}
|
||||
uint32_t period = rtc_slowck_cali(CALI_RTC_MUX, 128);
|
||||
uint32_t cycle_l, cycle_h;
|
||||
rtc_usec2rtc(time_in_us >> 32, time_in_us, period, &cycle_h, &cycle_l);
|
||||
rtc_slp_prep_lite(1, 0);
|
||||
rtc_sleep(cycle_h, cycle_l, TIMER_EXPIRE_EN, 0);
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void system_deep_sleep(uint64_t) __attribute__((alias("esp_deep_sleep")));
|
||||
|
|
41
components/esp32/hw_random.c
Normal file
41
components/esp32/hw_random.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 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.
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "esp_attr.h"
|
||||
#include "soc/wdev_reg.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "xtensa/core-macros.h"
|
||||
|
||||
uint32_t IRAM_ATTR esp_random(void)
|
||||
{
|
||||
/* The PRNG which implements WDEV_RANDOM register gets 2 bits
|
||||
* of extra entropy from a hardware randomness source every APB clock cycle.
|
||||
* To make sure entropy is not drained faster than it is added,
|
||||
* this function needs to wait for at least 16 APB clock cycles after reading
|
||||
* previous word. This implementation may actually wait a bit longer
|
||||
* due to extra time spent in arithmetic and branch statements.
|
||||
*/
|
||||
|
||||
static uint32_t last_ccount = 0;
|
||||
uint32_t ccount;
|
||||
do {
|
||||
ccount = XTHAL_GET_CCOUNT();
|
||||
} while (ccount - last_ccount < XT_CLOCK_FREQ / APB_CLK_FREQ * 16);
|
||||
last_ccount = ccount;
|
||||
return REG_READ(WDEV_RND_REG);
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#include <string.h>
|
||||
#include "hwcrypto/aes.h"
|
||||
#include "rom/aes.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include <sys/lock.h>
|
||||
|
||||
static _lock_t aes_lock;
|
||||
|
@ -36,14 +37,23 @@ void esp_aes_acquire_hardware( void )
|
|||
{
|
||||
/* newlib locks lazy initialize on ESP-IDF */
|
||||
_lock_acquire(&aes_lock);
|
||||
ets_aes_enable();
|
||||
/* Enable AES hardware */
|
||||
REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
|
||||
/* Clear reset on digital signature & secure boot units,
|
||||
otherwise AES unit is held in reset also. */
|
||||
REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
|
||||
DPORT_PERI_EN_AES
|
||||
| DPORT_PERI_EN_DIGITAL_SIGNATURE
|
||||
| DPORT_PERI_EN_SECUREBOOT);
|
||||
}
|
||||
|
||||
void esp_aes_release_hardware( void )
|
||||
{
|
||||
uint8_t zero[256/8] = { 0 };
|
||||
ets_aes_setkey_enc(zero, AES256);
|
||||
ets_aes_disable();
|
||||
/* Disable AES hardware */
|
||||
REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_AES);
|
||||
/* Don't return other units to reset, as this pulls
|
||||
reset on RSA & SHA units, respectively. */
|
||||
REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES);
|
||||
_lock_release(&aes_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,242 +26,264 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/lock.h>
|
||||
#include <byteswap.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "hwcrypto/sha.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/hwcrypto_reg.h"
|
||||
|
||||
|
||||
static _lock_t sha_lock;
|
||||
|
||||
void esp_sha_acquire_hardware( void )
|
||||
{
|
||||
/* newlib locks lazy initialize on ESP-IDF */
|
||||
_lock_acquire(&sha_lock);
|
||||
ets_sha_enable();
|
||||
inline static uint32_t SHA_LOAD_REG(esp_sha_type sha_type) {
|
||||
return SHA_1_LOAD_REG + sha_type * 0x10;
|
||||
}
|
||||
|
||||
void esp_sha_release_hardware( void )
|
||||
{
|
||||
/* Want to empty internal SHA buffers where possible,
|
||||
need to check if this is sufficient for this. */
|
||||
SHA_CTX zero = { 0 };
|
||||
ets_sha_init(&zero);
|
||||
ets_sha_disable();
|
||||
_lock_release(&sha_lock);
|
||||
inline static uint32_t SHA_BUSY_REG(esp_sha_type sha_type) {
|
||||
return SHA_1_BUSY_REG + sha_type * 0x10;
|
||||
}
|
||||
|
||||
/* Generic esp_shaX_update implementation */
|
||||
static void esp_sha_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen, size_t block_size)
|
||||
inline static uint32_t SHA_START_REG(esp_sha_type sha_type) {
|
||||
return SHA_1_START_REG + sha_type * 0x10;
|
||||
}
|
||||
|
||||
inline static uint32_t SHA_CONTINUE_REG(esp_sha_type sha_type) {
|
||||
return SHA_1_CONTINUE_REG + sha_type * 0x10;
|
||||
}
|
||||
|
||||
/* Single lock for SHA engine memory block
|
||||
*/
|
||||
static _lock_t memory_block_lock;
|
||||
|
||||
typedef struct {
|
||||
_lock_t lock;
|
||||
bool in_use;
|
||||
} sha_engine_state;
|
||||
|
||||
/* Pointer to state of each concurrent SHA engine.
|
||||
|
||||
Indexes:
|
||||
0 = SHA1
|
||||
1 = SHA2_256
|
||||
2 = SHA2_384 or SHA2_512
|
||||
*/
|
||||
static sha_engine_state engine_states[3];
|
||||
|
||||
/* Index into the sha_engine_state array */
|
||||
inline static size_t sha_engine_index(esp_sha_type type) {
|
||||
switch(type) {
|
||||
case SHA1:
|
||||
return 0;
|
||||
case SHA2_256:
|
||||
return 1;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return state & digest length (in bytes) for a given SHA type */
|
||||
inline static size_t sha_length(esp_sha_type type) {
|
||||
switch(type) {
|
||||
case SHA1:
|
||||
return 20;
|
||||
case SHA2_256:
|
||||
return 32;
|
||||
case SHA2_384:
|
||||
return 64;
|
||||
case SHA2_512:
|
||||
return 64;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return block size (in bytes) for a given SHA type */
|
||||
inline static size_t block_length(esp_sha_type type) {
|
||||
switch(type) {
|
||||
case SHA1:
|
||||
case SHA2_256:
|
||||
return 64;
|
||||
case SHA2_384:
|
||||
case SHA2_512:
|
||||
return 128;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_sha_lock_memory_block(void)
|
||||
{
|
||||
/* Feed the SHA engine one block at a time */
|
||||
_lock_acquire(&memory_block_lock);
|
||||
}
|
||||
|
||||
void esp_sha_unlock_memory_block(void)
|
||||
{
|
||||
_lock_release(&memory_block_lock);
|
||||
}
|
||||
|
||||
/* Lock to hold when changing SHA engine state,
|
||||
allows checking of sha_engines_all_idle()
|
||||
*/
|
||||
static _lock_t state_change_lock;
|
||||
|
||||
inline static bool sha_engines_all_idle() {
|
||||
return !engine_states[0].in_use
|
||||
&& !engine_states[1].in_use
|
||||
&& !engine_states[2].in_use;
|
||||
}
|
||||
|
||||
static void esp_sha_lock_engine_inner(sha_engine_state *engine);
|
||||
|
||||
bool esp_sha_try_lock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
if(_lock_try_acquire(&engine->lock) != 0) {
|
||||
/* This SHA engine is already in use */
|
||||
return false;
|
||||
} else {
|
||||
esp_sha_lock_engine_inner(engine);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_sha_lock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
_lock_acquire(&engine->lock);
|
||||
esp_sha_lock_engine_inner(engine);
|
||||
}
|
||||
|
||||
static void esp_sha_lock_engine_inner(sha_engine_state *engine)
|
||||
{
|
||||
_lock_acquire(&state_change_lock);
|
||||
|
||||
if (sha_engines_all_idle()) {
|
||||
/* Enable SHA hardware */
|
||||
REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
|
||||
/* also clear reset on secure boot, otherwise SHA is held in reset */
|
||||
REG_CLR_BIT(DPORT_PERI_RST_EN_REG,
|
||||
DPORT_PERI_EN_SHA
|
||||
| DPORT_PERI_EN_SECUREBOOT);
|
||||
ets_sha_enable();
|
||||
}
|
||||
|
||||
_lock_release(&state_change_lock);
|
||||
|
||||
assert( !engine->in_use && "in_use flag should be cleared" );
|
||||
engine->in_use = true;
|
||||
}
|
||||
|
||||
|
||||
void esp_sha_unlock_engine(esp_sha_type sha_type)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
|
||||
_lock_acquire(&state_change_lock);
|
||||
|
||||
assert( engine->in_use && "in_use flag should be set" );
|
||||
engine->in_use = false;
|
||||
|
||||
if (sha_engines_all_idle()) {
|
||||
/* Disable SHA hardware */
|
||||
/* Don't assert reset on secure boot, otherwise AES is held in reset */
|
||||
REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_SHA);
|
||||
REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_SHA);
|
||||
}
|
||||
|
||||
_lock_release(&state_change_lock);
|
||||
|
||||
_lock_release(&engine->lock);
|
||||
}
|
||||
|
||||
void esp_sha_wait_idle(void)
|
||||
{
|
||||
while(REG_READ(SHA_1_BUSY_REG) == 1) {}
|
||||
while(REG_READ(SHA_256_BUSY_REG) == 1) {}
|
||||
while(REG_READ(SHA_384_BUSY_REG) == 1) {}
|
||||
while(REG_READ(SHA_512_BUSY_REG) == 1) {}
|
||||
}
|
||||
|
||||
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
assert(engine->in_use && "SHA engine should be locked" );
|
||||
|
||||
esp_sha_lock_memory_block();
|
||||
|
||||
esp_sha_wait_idle();
|
||||
|
||||
REG_WRITE(SHA_LOAD_REG(sha_type), 1);
|
||||
while(REG_READ(SHA_BUSY_REG(sha_type)) == 1) { }
|
||||
|
||||
uint32_t *digest_state_words = (uint32_t *)digest_state;
|
||||
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
|
||||
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
|
||||
/* for these ciphers using 64-bit states, swap each pair of words */
|
||||
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
|
||||
digest_state_words[i+1] = reg_addr_buf[i];
|
||||
digest_state_words[i]= reg_addr_buf[i+1];
|
||||
}
|
||||
} else {
|
||||
memcpy(digest_state_words, reg_addr_buf, sha_length(sha_type));
|
||||
}
|
||||
asm volatile ("memw");
|
||||
|
||||
esp_sha_unlock_memory_block();
|
||||
}
|
||||
|
||||
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)
|
||||
{
|
||||
sha_engine_state *engine = &engine_states[sha_engine_index(sha_type)];
|
||||
assert(engine->in_use && "SHA engine should be locked" );
|
||||
|
||||
esp_sha_lock_memory_block();
|
||||
|
||||
esp_sha_wait_idle();
|
||||
|
||||
/* Fill the data block */
|
||||
uint32_t *reg_addr_buf = (uint32_t *)(SHA_TEXT_BASE);
|
||||
uint32_t *data_words = (uint32_t *)data_block;
|
||||
for (int i = 0; i < block_length(sha_type) / 4; i++) {
|
||||
reg_addr_buf[i] = __bswap_32(data_words[i]);
|
||||
}
|
||||
asm volatile ("memw");
|
||||
|
||||
if(is_first_block) {
|
||||
REG_WRITE(SHA_START_REG(sha_type), 1);
|
||||
} else {
|
||||
REG_WRITE(SHA_CONTINUE_REG(sha_type), 1);
|
||||
}
|
||||
|
||||
esp_sha_unlock_memory_block();
|
||||
|
||||
/* Note: deliberately not waiting for this operation to complete,
|
||||
as a performance tweak - delay waiting until the next time we need the SHA
|
||||
unit, instead.
|
||||
*/
|
||||
}
|
||||
|
||||
void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, unsigned char *output)
|
||||
{
|
||||
size_t block_len = block_length(sha_type);
|
||||
|
||||
esp_sha_lock_engine(sha_type);
|
||||
|
||||
SHA_CTX ctx;
|
||||
ets_sha_init(&ctx);
|
||||
while(ilen > 0) {
|
||||
size_t chunk_len = (ilen > block_size) ? block_size : ilen;
|
||||
ets_sha_update(&ctx->context, ctx->context_type, input, chunk_len * 8);
|
||||
size_t chunk_len = (ilen > block_len) ? block_len : ilen;
|
||||
esp_sha_lock_memory_block();
|
||||
esp_sha_wait_idle();
|
||||
ets_sha_update(&ctx, sha_type, input, chunk_len * 8);
|
||||
esp_sha_unlock_memory_block();
|
||||
input += chunk_len;
|
||||
ilen -= chunk_len;
|
||||
}
|
||||
esp_sha_lock_memory_block();
|
||||
esp_sha_wait_idle();
|
||||
ets_sha_finish(&ctx, sha_type, output);
|
||||
esp_sha_unlock_memory_block();
|
||||
|
||||
esp_sha_unlock_engine(sha_type);
|
||||
}
|
||||
|
||||
void esp_sha1_init( esp_sha_context *ctx )
|
||||
{
|
||||
bzero( ctx, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha1_free( esp_sha_context *ctx )
|
||||
{
|
||||
if ( ctx == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bzero( ctx, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha1_clone( esp_sha_context *dst, const esp_sha_context *src )
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 context setup
|
||||
*/
|
||||
void esp_sha1_start( esp_sha_context *ctx )
|
||||
{
|
||||
ctx->context_type = SHA1;
|
||||
esp_sha_acquire_hardware();
|
||||
ets_sha_init(&ctx->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 process buffer
|
||||
*/
|
||||
void esp_sha1_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen )
|
||||
{
|
||||
esp_sha_update(ctx, input, ilen, 64);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-1 final digest
|
||||
*/
|
||||
void esp_sha1_finish( esp_sha_context *ctx, unsigned char output[20] )
|
||||
{
|
||||
ets_sha_finish(&ctx->context, ctx->context_type, output);
|
||||
esp_sha_release_hardware();
|
||||
}
|
||||
|
||||
/* Full SHA-1 calculation */
|
||||
void esp_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] )
|
||||
{
|
||||
esp_sha_context ctx;
|
||||
|
||||
esp_sha1_init( &ctx );
|
||||
esp_sha1_start( &ctx );
|
||||
esp_sha1_update( &ctx, input, ilen );
|
||||
esp_sha1_finish( &ctx, output );
|
||||
esp_sha1_free( &ctx );
|
||||
}
|
||||
|
||||
void esp_sha256_init( esp_sha_context *ctx )
|
||||
{
|
||||
bzero( ctx, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha256_free( esp_sha_context *ctx )
|
||||
{
|
||||
if ( ctx == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bzero( ctx, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha256_clone( esp_sha_context *dst, const esp_sha_context *src )
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-256 context setup
|
||||
*/
|
||||
void esp_sha256_start( esp_sha_context *ctx, int is224 )
|
||||
{
|
||||
if ( is224 == 0 ) {
|
||||
/* SHA-256 */
|
||||
ctx->context_type = SHA2_256;
|
||||
esp_sha_acquire_hardware();
|
||||
ets_sha_init(&ctx->context);
|
||||
} else {
|
||||
/* SHA-224 is not supported! */
|
||||
ctx->context_type = SHA_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-256 process buffer
|
||||
*/
|
||||
void esp_sha256_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen )
|
||||
{
|
||||
if( ctx->context_type == SHA2_256 ) {
|
||||
esp_sha_update(ctx, input, ilen, 64);
|
||||
}
|
||||
/* SHA-224 is a no-op */
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-256 final digest
|
||||
*/
|
||||
void esp_sha256_finish( esp_sha_context *ctx, unsigned char output[32] )
|
||||
{
|
||||
if ( ctx->context_type == SHA2_256 ) {
|
||||
ets_sha_finish(&ctx->context, ctx->context_type, output);
|
||||
esp_sha_release_hardware();
|
||||
} else {
|
||||
/* No hardware SHA-224 support, but mbedTLS API doesn't allow failure.
|
||||
For now, zero the output to make it clear it's not valid. */
|
||||
bzero( output, 28 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Full SHA-256 calculation
|
||||
*/
|
||||
void esp_sha256( const unsigned char *input, size_t ilen, unsigned char output[32], int is224 )
|
||||
{
|
||||
esp_sha_context ctx;
|
||||
|
||||
esp_sha256_init( &ctx );
|
||||
esp_sha256_start( &ctx, is224 );
|
||||
esp_sha256_update( &ctx, input, ilen );
|
||||
esp_sha256_finish( &ctx, output );
|
||||
esp_sha256_free( &ctx );
|
||||
}
|
||||
|
||||
|
||||
/////
|
||||
void esp_sha512_init( esp_sha_context *ctx )
|
||||
{
|
||||
memset( ctx, 0, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha512_free( esp_sha_context *ctx )
|
||||
{
|
||||
if ( ctx == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bzero( ctx, sizeof( esp_sha_context ) );
|
||||
}
|
||||
|
||||
void esp_sha512_clone( esp_sha_context *dst, const esp_sha_context *src )
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-512 context setup
|
||||
*/
|
||||
void esp_sha512_start( esp_sha_context *ctx, int is384 )
|
||||
{
|
||||
if ( is384 == 0 ) {
|
||||
/* SHA-512 */
|
||||
ctx->context_type = SHA2_512;
|
||||
} else {
|
||||
/* SHA-384 */
|
||||
ctx->context_type = SHA2_384;
|
||||
}
|
||||
esp_sha_acquire_hardware();
|
||||
ets_sha_init(&ctx->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-512 process buffer
|
||||
*/
|
||||
void esp_sha512_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen )
|
||||
{
|
||||
esp_sha_update(ctx, input, ilen, 128);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA-512 final digest
|
||||
*/
|
||||
void esp_sha512_finish( esp_sha_context *ctx, unsigned char output[64] )
|
||||
{
|
||||
ets_sha_finish(&ctx->context, ctx->context_type, output);
|
||||
esp_sha_release_hardware();
|
||||
}
|
||||
|
||||
/*
|
||||
* Full SHA-512 calculation
|
||||
*/
|
||||
void esp_sha512( const unsigned char *input, size_t ilen, unsigned char output[64], int is384 )
|
||||
{
|
||||
esp_sha_context ctx;
|
||||
|
||||
esp_sha512_init( &ctx );
|
||||
esp_sha512_start( &ctx, is384 );
|
||||
esp_sha512_update( &ctx, input, ilen );
|
||||
esp_sha512_finish( &ctx, output );
|
||||
esp_sha512_free( &ctx );
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
|
|
|
@ -30,25 +30,34 @@ extern "C" {
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Set the chip to deep-sleep mode.
|
||||
*
|
||||
* The device will automatically wake up after the deep-sleep time set
|
||||
* by the users. Upon waking up, the device boots up from user_init.
|
||||
*
|
||||
* @attention The parameter time_in_us to be "uint64" is for further development.
|
||||
* Only the low 32 bits of parameter time_in_us are avalable now.
|
||||
*
|
||||
* @param uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
void system_deep_sleep(uint64_t time_in_us);
|
||||
* @brief Enter deep-sleep mode
|
||||
*
|
||||
* The device will automatically wake up after the deep-sleep time
|
||||
* Upon waking up, the device calls deep sleep wake stub, and then proceeds
|
||||
* to load application.
|
||||
*
|
||||
* This function does not return.
|
||||
*
|
||||
* @param time_in_us deep-sleep time, unit: microsecond
|
||||
*/
|
||||
void esp_deep_sleep(uint64_t time_in_us) __attribute__((noreturn));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enter deep-sleep mode
|
||||
*
|
||||
* Function has been renamed to esp_deep_sleep.
|
||||
* This name is deprecated and will be removed in a future version.
|
||||
*
|
||||
* @param time_in_us deep-sleep time, unit: microsecond
|
||||
*/
|
||||
void system_deep_sleep(uint64_t time_in_us) __attribute__((noreturn, deprecated));
|
||||
|
||||
/**
|
||||
* @brief Default stub to run on wake from deep sleep.
|
||||
*
|
||||
* Allows for executing code immediately on wake from sleep, before
|
||||
* the software bootloader or esp-idf app has started up.
|
||||
* the software bootloader or ESP-IDF app has started up.
|
||||
*
|
||||
* This function is weak-linked, so you can implement your own version
|
||||
* to run code immediately when the chip wakes from
|
||||
|
|
|
@ -44,6 +44,7 @@ typedef enum {
|
|||
SYSTEM_EVENT_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
|
||||
SYSTEM_EVENT_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
SYSTEM_EVENT_AP_STA_GOT_IP6, /**< ESP32 station or ap interface v6IP addr is preferred */
|
||||
SYSTEM_EVENT_MAX
|
||||
} system_event_id_t;
|
||||
|
||||
|
@ -79,7 +80,11 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
|
||||
}system_event_sta_wps_er_pin_t;
|
||||
} system_event_sta_wps_er_pin_t;
|
||||
|
||||
typedef struct {
|
||||
tcpip_adapter_ip6_info_t ip6_info;
|
||||
} system_event_ap_sta_got_ip6_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
||||
|
@ -106,6 +111,7 @@ typedef union {
|
|||
system_event_ap_staconnected_t sta_connected; /**< a station connected to ESP32 soft-AP */
|
||||
system_event_ap_stadisconnected_t sta_disconnected; /**< a station disconnected to ESP32 soft-AP */
|
||||
system_event_ap_probe_req_rx_t ap_probereqrecved; /**< ESP32 soft-AP receive probe request packet */
|
||||
system_event_ap_sta_got_ip6_t got_ip6; /**< ESP32 station or ap ipv6 addr state change to preferred */
|
||||
} system_event_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -82,126 +82,6 @@ extern "C" {
|
|||
#define ESP_INTR_DISABLE(inum) \
|
||||
xt_ints_off((1<<inum))
|
||||
|
||||
#define ESP_CCOMPARE_INTR_ENBALE() \
|
||||
ESP_INTR_ENABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_CCOMPARE_INTR_DISBALE() \
|
||||
ESP_INTR_DISABLE(ETS_CCOMPARE_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI1_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_PWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PWM_INUM)
|
||||
|
||||
#define ESP_SPI2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI2_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_SPI3_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SPI3_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S0_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S0_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_I2S1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_I2S1_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_MPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_MPWM_INUM)
|
||||
|
||||
#define ESP_EPWM_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_EPWM_INUM)
|
||||
|
||||
#define ESP_BB_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_BB_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_BB_INUM)
|
||||
|
||||
#define ESP_UART0_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_UART0_INUM)
|
||||
|
||||
#define ESP_UART0_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_UART0_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_LEDC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_LEDC_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_GPIO_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_GPIO_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_WDT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_WDT_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC1_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER1_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_FRC2_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_FRC_TIMER2_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_RTC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RTC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_SLC_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_SLC_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_PCNT_INTR_DISABLE() \
|
||||
ESP_INTR_DISABLE(ETS_PCNT_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_ENABLE() \
|
||||
ESP_INTR_ENABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#define ESP_RMT_CTRL_DIABLE() \
|
||||
ESP_INTR_DISABLE(ETS_RMT_CTRL_INUM)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#define __ESP_SYSTEM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_deepsleep.h"
|
||||
|
||||
|
@ -24,166 +24,107 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \defgroup System_APIs System APIs
|
||||
* @brief System APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup System_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @attention application don't need to call this function anymore. It do nothing and will
|
||||
* be removed in future version.
|
||||
*/
|
||||
void system_init(void) __attribute__ ((deprecated));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get information of the SDK version.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return Information of the SDK version.
|
||||
*/
|
||||
const char *system_get_sdk_version(void);
|
||||
|
||||
/**
|
||||
* @brief Reset to default settings.
|
||||
*
|
||||
* Reset to default settings of the following APIs : wifi_station_set_auto_connect,
|
||||
* wifi_set_phy_mode, wifi_softap_set_config related, wifi_station_set_config
|
||||
* related, and wifi_set_opmode.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
* Function has been deprecated, please use esp_wifi_restore instead.
|
||||
* This name will be removed in a future release.
|
||||
*/
|
||||
void system_restore(void);
|
||||
void system_restore(void) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Restart PRO and APP CPUs.
|
||||
*
|
||||
* This function can be called both from PRO and APP CPUs.
|
||||
* After successful restart, CPU reset reason will be SW_CPU_RESET.
|
||||
* Peripherals (except for WiFi, BT, UART0, SPI1, and legacy timers) are not reset.
|
||||
* This function does not return.
|
||||
*/
|
||||
void esp_restart(void) __attribute__ ((noreturn));
|
||||
|
||||
/**
|
||||
* @brief Restart system.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return null
|
||||
* Function has been renamed to esp_restart.
|
||||
* This name will be removed in a future release.
|
||||
*/
|
||||
void system_restart(void);
|
||||
void system_restart(void) __attribute__ ((deprecated, noreturn));
|
||||
|
||||
/**
|
||||
* @brief Get system time, unit: microsecond.
|
||||
*
|
||||
* @param null
|
||||
*
|
||||
* @return System time, unit: microsecond.
|
||||
* This function is deprecated. Use 'gettimeofday' function for 64-bit precision.
|
||||
* This definition will be removed in a future release.
|
||||
*/
|
||||
uint32_t system_get_time(void);
|
||||
uint32_t system_get_time(void) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Get the size of available heap.
|
||||
*
|
||||
* @param null
|
||||
* Note that the returned value may be larger than the maximum contiguous block
|
||||
* which can be allocated.
|
||||
*
|
||||
* @return Available heap size.
|
||||
* @return Available heap size, in bytes.
|
||||
*/
|
||||
uint32_t system_get_free_heap_size(void);
|
||||
uint32_t esp_get_free_heap_size(void);
|
||||
|
||||
/**
|
||||
* @brief Get RTC time, unit: RTC clock cycle.
|
||||
* @brief Get the size of available heap.
|
||||
*
|
||||
* @param null
|
||||
* Function has been renamed to esp_get_free_heap_size.
|
||||
* This name will be removed in a future release.
|
||||
*
|
||||
* @return RTC time.
|
||||
* @return Available heap size, in bytes.
|
||||
*/
|
||||
uint64_t system_get_rtc_time(void);
|
||||
uint32_t system_get_free_heap_size(void) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Read user data from the RTC memory.
|
||||
*
|
||||
* The user data segment (1024 bytes, as shown below) is used to store user data.
|
||||
*
|
||||
* |<---- system data(512 bytes) ---->|<----------- user data(1024 bytes) --------->|
|
||||
*
|
||||
* @attention Read and write unit for data stored in the RTC memory is 4 bytes.
|
||||
* @attention src_addr is the block number (4 bytes per block). So when reading data
|
||||
* at the beginning of the user data segment, src_addr will be 512/4 = 128,
|
||||
* n will be data length.
|
||||
*
|
||||
* @param uint16 src : source address of rtc memory, src_addr >= 128
|
||||
* @param void *dst : data pointer
|
||||
* @param uint16 n : data length, unit: byte
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_rtc_mem_read(uint16_t src, void *dst, uint16_t n);
|
||||
|
||||
/**
|
||||
* @brief Write user data to the RTC memory.
|
||||
*
|
||||
* During deep-sleep, only RTC is working. So users can store their data
|
||||
* in RTC memory if it is needed. The user data segment below (1024 bytes)
|
||||
* is used to store the user data.
|
||||
*
|
||||
* |<---- system data(512 bytes) ---->|<----------- user data(1024 bytes) --------->|
|
||||
*
|
||||
* @attention Read and write unit for data stored in the RTC memory is 4 bytes.
|
||||
* @attention src_addr is the block number (4 bytes per block). So when storing data
|
||||
* at the beginning of the user data segment, src_addr will be 512/4 = 128,
|
||||
* n will be data length.
|
||||
*
|
||||
* @param uint16 src : source address of rtc memory, src_addr >= 128
|
||||
* @param void *dst : data pointer
|
||||
* @param uint16 n : data length, unit: byte
|
||||
*
|
||||
* @return true : succeed
|
||||
* @return false : fail
|
||||
*/
|
||||
bool system_rtc_mem_write(uint16_t dst, const void *src, uint16_t n);
|
||||
|
||||
/** \defgroup System_boot_APIs Boot APIs
|
||||
* @brief boot APIs
|
||||
*/
|
||||
|
||||
/** @addtogroup System_boot_APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** \defgroup Hardware_MAC_APIs Hardware MAC APIs
|
||||
* @brief Hardware MAC address APIs
|
||||
*
|
||||
* In WiFi MAC, only ESP32 station MAC is the hardware MAC, ESP32 softAP MAC is a software MAC
|
||||
* calculated from ESP32 station MAC.
|
||||
* So users need to call wifi_get_macaddr to query the ESP32 softAP MAC if ESP32 station MAC changed.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @addtogroup Hardware_MAC_APIs
|
||||
* @{
|
||||
*/
|
||||
* @brief Get one random 32-bit word from hardware RNG
|
||||
*
|
||||
* @return random value between 0 and UINT32_MAX
|
||||
*/
|
||||
uint32_t esp_random(void);
|
||||
|
||||
/**
|
||||
* @brief Read hardware MAC address.
|
||||
*
|
||||
* @param uint8 mac[6] : the hardware MAC address, length: 6 bytes.
|
||||
* In WiFi MAC, only ESP32 station MAC is the hardware MAC, ESP32 softAP MAC is a software MAC
|
||||
* calculated from ESP32 station MAC.
|
||||
* So users need to call esp_wifi_get_macaddr to query the ESP32 softAP MAC if ESP32 station MAC changed.
|
||||
*
|
||||
* @return esp_err_t
|
||||
* @param mac hardware MAC address, length: 6 bytes.
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t system_efuse_read_mac(uint8_t mac[6]);
|
||||
|
||||
esp_err_t esp_efuse_read_mac(uint8_t* mac);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @brief Read hardware MAC address.
|
||||
*
|
||||
* Function has been renamed to esp_efuse_read_mac.
|
||||
* This name will be removed in a future release.
|
||||
*
|
||||
* @param mac hardware MAC address, length: 6 bytes.
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
|
||||
esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated));
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
* Get SDK version
|
||||
*
|
||||
* This function is deprecated and will be removed in a future release.
|
||||
*
|
||||
* @return constant string "master"
|
||||
*/
|
||||
const char* system_get_sdk_version(void) __attribute__ ((deprecated));
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -22,52 +22,4 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define __ATTRIB_PACK __attribute__ ((packed))
|
||||
#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2)))
|
||||
#define __ATTRIB_NORETURN __attribute__ ((noreturn))
|
||||
#define __ATTRIB_ALIGN(x) __attribute__ ((aligned((x))))
|
||||
#define INLINE __inline__
|
||||
|
||||
#define LOCAL static
|
||||
|
||||
/* probably should not put STATUS here */
|
||||
typedef enum {
|
||||
OK = 0,
|
||||
FAIL,
|
||||
PENDING,
|
||||
BUSY,
|
||||
CANCEL,
|
||||
} STATUS;
|
||||
|
||||
//#define _LITTLE_ENDIAN 1234
|
||||
//#define _BYTE_ORDER == _LITTLE_ENDIAN
|
||||
|
||||
#define ASSERT( x ) do { \
|
||||
if (!(x)) { \
|
||||
printf("%s %u\n", __FILE__, __LINE__); \
|
||||
while (1) { \
|
||||
asm volatile("nop"); \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* #if __GNUC_PREREQ__(4, 1) */
|
||||
#ifndef __GNUC__
|
||||
#if 1
|
||||
#define __offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#else
|
||||
#define __offsetof(type, field) ((size_t)(&((type *)0)->field))
|
||||
#endif
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
|
||||
/* Macros for counting and rounding. */
|
||||
#ifndef howmany
|
||||
#define howmany(x, y) (((x)+((y)-1))/(y))
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, member) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
(type *)( (char *)__mptr - __offsetof(type,member) );})
|
||||
|
||||
#endif /* __ESP_TYPES_H__ */
|
||||
|
|
|
@ -186,6 +186,21 @@ esp_err_t esp_wifi_start(void);
|
|||
*/
|
||||
esp_err_t esp_wifi_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Restore WiFi stack persistent settings to default values
|
||||
*
|
||||
* This function will reset settings made using the following APIs:
|
||||
* - esp_wifi_get_auto_connect,
|
||||
* - esp_wifi_set_protocol,
|
||||
* - esp_wifi_set_config related
|
||||
* - esp_wifi_set_mode
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
* - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
|
||||
*/
|
||||
esp_err_t esp_wifi_restore(void);
|
||||
|
||||
/**
|
||||
* @brief Connect the ESP32 WiFi station to the AP.
|
||||
*
|
||||
|
|
|
@ -43,10 +43,9 @@ extern "C" {
|
|||
/**
|
||||
* @brief get whether the wifi driver is allowed to transmit data or not
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return true : upper layer should stop to transmit data to wifi driver
|
||||
* @return false : upper layer can transmit data to wifi driver
|
||||
* @return
|
||||
* - true : upper layer should stop to transmit data to wifi driver
|
||||
* - false : upper layer can transmit data to wifi driver
|
||||
*/
|
||||
bool esp_wifi_internal_tx_is_stop(void);
|
||||
|
||||
|
@ -54,8 +53,6 @@ bool esp_wifi_internal_tx_is_stop(void);
|
|||
* @brief free the rx buffer which allocated by wifi driver
|
||||
*
|
||||
* @param void* buffer: rx buffer pointer
|
||||
*
|
||||
* @return nonoe
|
||||
*/
|
||||
void esp_wifi_internal_free_rx_buffer(void* buffer);
|
||||
|
||||
|
@ -78,7 +75,6 @@ int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, u16_t len);
|
|||
* @brief The WiFi RX callback function
|
||||
*
|
||||
* Each time the WiFi need to forward the packets to high layer, the callback function will be called
|
||||
*
|
||||
*/
|
||||
typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb);
|
||||
|
||||
|
@ -90,18 +86,18 @@ typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb);
|
|||
* @param wifi_interface_t ifx : interface
|
||||
* @param wifi_rxcb_t fn : WiFi RX callback
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
esp_err_t esp_wifi_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn);
|
||||
|
||||
/**
|
||||
* @brief Notify WIFI driver that the station got ip successfully
|
||||
*
|
||||
* @param none
|
||||
*
|
||||
* @return ESP_OK : succeed
|
||||
* @return others : fail
|
||||
* @return
|
||||
* - ESP_OK : succeed
|
||||
* - others : fail
|
||||
*/
|
||||
esp_err_t esp_wifi_internal_set_sta_ip(void);
|
||||
|
||||
|
|
|
@ -1,246 +1,200 @@
|
|||
/*
|
||||
* ESP32 hardware accelerated SHA1/256/512 implementation
|
||||
* based on mbedTLS FIPS-197 compliant version.
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
// 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 _ESP_SHA_H_
|
||||
#define _ESP_SHA_H_
|
||||
|
||||
#include "rom/sha.h"
|
||||
|
||||
#include "esp_types.h"
|
||||
|
||||
/** @brief Low-level support functions for the hardware SHA engine
|
||||
*
|
||||
* @note If you're looking for a SHA API to use, try mbedtls component
|
||||
* mbedtls/shaXX.h. That API supports hardware acceleration.
|
||||
*
|
||||
* The API in this header provides some building blocks for implementing a
|
||||
* full SHA API such as the one in mbedtls, and also a basic SHA function esp_sha().
|
||||
*
|
||||
* Some technical details about the hardware SHA engine:
|
||||
*
|
||||
* - SHA accelerator engine calculates one digest at a time, per SHA
|
||||
* algorithm type. It initialises and maintains the digest state
|
||||
* internally. It is possible to read out an in-progress SHA digest
|
||||
* state, but it is not possible to restore a SHA digest state
|
||||
* into the engine.
|
||||
*
|
||||
* - The memory block SHA_TEXT_BASE is shared between all SHA digest
|
||||
* engines, so all engines must be idle before this memory block is
|
||||
* modified.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief SHA-1 context structure
|
||||
*/
|
||||
typedef struct {
|
||||
/* both types defined in rom/sha.h */
|
||||
SHA_CTX context;
|
||||
enum SHA_TYPE context_type;
|
||||
} esp_sha_context;
|
||||
/* Defined in rom/sha.h */
|
||||
typedef enum SHA_TYPE esp_sha_type;
|
||||
|
||||
/**
|
||||
* \brief Lock access to SHA hardware unit
|
||||
/** @brief Calculate SHA1 or SHA2 sum of some data, using hardware SHA engine
|
||||
*
|
||||
* SHA hardware unit can only be used by one
|
||||
* consumer at a time.
|
||||
* @note For more versatile SHA calculations, where data doesn't need
|
||||
* to be passed all at once, try the mbedTLS mbedtls/shaX.h APIs. The
|
||||
* hardware-accelerated mbedTLS implementation is also faster when
|
||||
* hashing large amounts of data.
|
||||
*
|
||||
* esp_sha_xxx API calls automatically manage locking & unlocking of
|
||||
* hardware, this function is only needed if you want to call
|
||||
* ets_sha_xxx functions directly.
|
||||
*/
|
||||
void esp_sha_acquire_hardware( void );
|
||||
|
||||
/**
|
||||
* \brief Unlock access to SHA hardware unit
|
||||
* @note It is not necessary to lock any SHA hardware before calling
|
||||
* this function, thread safety is managed internally.
|
||||
*
|
||||
* esp_sha_xxx API calls automatically manage locking & unlocking of
|
||||
* hardware, this function is only needed if you want to call
|
||||
* ets_sha_xxx functions directly.
|
||||
*/
|
||||
void esp_sha_release_hardware( void );
|
||||
|
||||
/**
|
||||
* \brief Initialize SHA-1 context
|
||||
* @note If a TLS connection is open then this function may block
|
||||
* indefinitely waiting for a SHA engine to become available. Use the
|
||||
* mbedTLS SHA API to avoid this problem.
|
||||
*
|
||||
* \param ctx SHA-1 context to be initialized
|
||||
*/
|
||||
void esp_sha1_init( esp_sha_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief Clear SHA-1 context
|
||||
* @param sha_type SHA algorithm to use.
|
||||
*
|
||||
* \param ctx SHA-1 context to be cleared
|
||||
*/
|
||||
void esp_sha1_free( esp_sha_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief Clone (the state of) a SHA-1 context
|
||||
* @param input Input data buffer.
|
||||
*
|
||||
* \param dst The destination context
|
||||
* \param src The context to be cloned
|
||||
*/
|
||||
void esp_sha1_clone( esp_sha_context *dst, const esp_sha_context *src );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 context setup
|
||||
* @param ilen Length of input data in bytes.
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
* @param output Buffer for output SHA digest. Output is 20 bytes for
|
||||
* sha_type SHA1, 32 bytes for sha_type SHA2_256, 48 bytes for
|
||||
* sha_type SHA2_384, 64 bytes for sha_type SHA2_512.
|
||||
*/
|
||||
void esp_sha1_start( esp_sha_context *ctx );
|
||||
void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, unsigned char *output);
|
||||
|
||||
/**
|
||||
* \brief SHA-1 process buffer
|
||||
/* @brief Begin to execute a single SHA block operation
|
||||
*
|
||||
* \param ctx SHA-1 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void esp_sha1_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen );
|
||||
|
||||
/**
|
||||
* \brief SHA-1 final digest
|
||||
* @note This is a piece of a SHA algorithm, rather than an entire SHA
|
||||
* algorithm.
|
||||
*
|
||||
* \param ctx SHA-1 context
|
||||
* \param output SHA-1 checksum result
|
||||
*/
|
||||
void esp_sha1_finish( esp_sha_context *ctx, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief Calculate SHA-1 of input buffer
|
||||
* @note Call esp_sha_try_lock_engine() before calling this
|
||||
* function. Do not call esp_sha_lock_memory_block() beforehand, this
|
||||
* is done inside the function.
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output SHA-1 checksum result
|
||||
*/
|
||||
void esp_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] );
|
||||
|
||||
/**
|
||||
* \brief SHA-256 context structure
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Initialize SHA-256 context
|
||||
* @param sha_type SHA algorithm to use.
|
||||
*
|
||||
* \param ctx SHA-256 context to be initialized
|
||||
*/
|
||||
void esp_sha256_init( esp_sha_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief Clear SHA-256 context
|
||||
* @param data_block Pointer to block of data. Block size is
|
||||
* determined by algorithm (SHA1/SHA2_256 = 64 bytes,
|
||||
* SHA2_384/SHA2_512 = 128 bytes)
|
||||
*
|
||||
* \param ctx SHA-256 context to be cleared
|
||||
*/
|
||||
void esp_sha256_free( esp_sha_context *ctx );
|
||||
|
||||
/**
|
||||
* \brief Clone (the state of) a SHA-256 context
|
||||
* @param is_first_block If this parameter is true, the SHA state will
|
||||
* be initialised (with the initial state of the given SHA algorithm)
|
||||
* before the block is calculated. If false, the existing state of the
|
||||
* SHA engine will be used.
|
||||
*
|
||||
* \param dst The destination context
|
||||
* \param src The context to be cloned
|
||||
* @return As a performance optimisation, this function returns before
|
||||
* the SHA block operation is complete. Both this function and
|
||||
* esp_sha_read_state() will automatically wait for any previous
|
||||
* operation to complete before they begin. If using the SHA registers
|
||||
* directly in another way, call esp_sha_wait_idle() after calling this
|
||||
* function but before accessing the SHA registers.
|
||||
*/
|
||||
void esp_sha256_clone( esp_sha_context *dst, const esp_sha_context *src );
|
||||
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block);
|
||||
|
||||
/**
|
||||
* \brief SHA-256 context setup
|
||||
/** @brief Read out the current state of the SHA digest loaded in the engine.
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
* \param is224 0 = use SHA256, 1 = use SHA224
|
||||
*/
|
||||
void esp_sha256_start( esp_sha_context *ctx, int is224 );
|
||||
|
||||
/**
|
||||
* \brief SHA-256 process buffer
|
||||
* @note This is a piece of a SHA algorithm, rather than an entire SHA algorithm.
|
||||
*
|
||||
* \param ctx SHA-256 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
*/
|
||||
void esp_sha256_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen );
|
||||
|
||||
/**
|
||||
* \brief SHA-256 final digest
|
||||
* @note Call esp_sha_try_lock_engine() before calling this
|
||||
* function. Do not call esp_sha_lock_memory_block() beforehand, this
|
||||
* is done inside the function.
|
||||
*
|
||||
* \param ctx SHA-256 context
|
||||
* \param output SHA-224/256 checksum result
|
||||
*/
|
||||
void esp_sha256_finish( esp_sha_context *ctx, unsigned char output[32] );
|
||||
|
||||
/**
|
||||
* \brief Calculate SHA-256 of input buffer
|
||||
* If the SHA suffix padding block has been executed already, the
|
||||
* value that is read is the SHA digest (in big endian
|
||||
* format). Otherwise, the value that is read is an interim SHA state.
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output SHA-224/256 checksum result
|
||||
* \param is224 0 = use SHA256, 1 = use SHA224
|
||||
*/
|
||||
void esp_sha256( const unsigned char *input, size_t ilen, unsigned char output[32], int is224 );
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* \brief SHA-512 context structure
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Initialize SHA-512 context
|
||||
* @param sha_type SHA algorithm in use.
|
||||
*
|
||||
* @param state Pointer to a memory buffer to hold the SHA state. Size
|
||||
* is 20 bytes (SHA1), 64 bytes (SHA2_256), or 128 bytes (SHA2_384 or
|
||||
* SHA2_512).
|
||||
*
|
||||
* \param ctx SHA-512 context to be initialized
|
||||
*/
|
||||
void esp_sha512_init( esp_sha_context *ctx );
|
||||
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state);
|
||||
|
||||
/**
|
||||
* \brief Clear SHA-512 context
|
||||
* @brief Obtain exclusive access to a particular SHA engine
|
||||
*
|
||||
* \param ctx SHA-512 context to be cleared
|
||||
* @param sha_type Type of SHA engine to use.
|
||||
*
|
||||
* Blocks until engine is available. Note: Can block indefinitely
|
||||
* while a TLS connection is open, suggest using
|
||||
* esp_sha_try_lock_engine() and failing over to software SHA.
|
||||
*/
|
||||
void esp_sha512_free( esp_sha_context *ctx );
|
||||
void esp_sha_lock_engine(esp_sha_type sha_type);
|
||||
|
||||
/**
|
||||
* \brief Clone (the state of) a SHA-512 context
|
||||
* @brief Try and obtain exclusive access to a particular SHA engine
|
||||
*
|
||||
* \param dst The destination context
|
||||
* \param src The context to be cloned
|
||||
* @param sha_type Type of SHA engine to use.
|
||||
*
|
||||
* @return Returns true if the SHA engine is locked for exclusive
|
||||
* use. Call esp_sha_unlock_sha_engine() when done. Returns false if
|
||||
* the SHA engine is already in use, caller should use software SHA
|
||||
* algorithm for this digest.
|
||||
*/
|
||||
void esp_sha512_clone( esp_sha_context *dst, const esp_sha_context *src );
|
||||
bool esp_sha_try_lock_engine(esp_sha_type sha_type);
|
||||
|
||||
/**
|
||||
* \brief SHA-512 context setup
|
||||
* @brief Unlock an engine previously locked with esp_sha_lock_engine() or esp_sha_try_lock_engine()
|
||||
*
|
||||
* \param ctx context to be initialized
|
||||
* \param is384 0 = use SHA512, 1 = use SHA384
|
||||
* @param sha_type Type of engine to release.
|
||||
*/
|
||||
void esp_sha512_start( esp_sha_context *ctx, int is384 );
|
||||
void esp_sha_unlock_engine(esp_sha_type sha_type);
|
||||
|
||||
/**
|
||||
* \brief SHA-512 process buffer
|
||||
* @brief Acquire exclusive access to the SHA shared memory block at SHA_TEXT_BASE
|
||||
*
|
||||
* \param ctx SHA-512 context
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* This memory block is shared across all the SHA algorithm types.
|
||||
*
|
||||
* Caller should have already locked a SHA engine before calling this function.
|
||||
*
|
||||
* Note that it is possible to obtain exclusive access to the memory block even
|
||||
* while it is in use by the SHA engine. Caller should use esp_sha_wait_idle()
|
||||
* to ensure the SHA engine is not reading from the memory block in hardware.
|
||||
*
|
||||
* @note You do not need to lock the memory block before calling esp_sha_block() or esp_sha_read_digest_state(), these functions handle memory block locking internally.
|
||||
*
|
||||
* Call esp_sha_unlock_memory_block() when done.
|
||||
*/
|
||||
void esp_sha512_update( esp_sha_context *ctx, const unsigned char *input, size_t ilen );
|
||||
void esp_sha_lock_memory_block(void);
|
||||
|
||||
/**
|
||||
* \brief SHA-512 final digest
|
||||
* @brief Release exclusive access to the SHA register memory block at SHA_TEXT_BASE
|
||||
*
|
||||
* \param ctx SHA-512 context
|
||||
* \param output SHA-384/512 checksum result
|
||||
*/
|
||||
void esp_sha512_finish( esp_sha_context *ctx, unsigned char output[64] );
|
||||
|
||||
/**
|
||||
* \brief Calculate SHA-512 of input buffer.
|
||||
* Caller should have already locked a SHA engine before calling this function.
|
||||
*
|
||||
* \param input buffer holding the data
|
||||
* \param ilen length of the input data
|
||||
* \param output SHA-384/512 checksum result
|
||||
* \param is384 0 = use SHA512, 1 = use SHA384
|
||||
* Call following esp_sha_lock_memory_block().
|
||||
*/
|
||||
void esp_sha512( const unsigned char *input, size_t ilen, unsigned char output[64], int is384 );
|
||||
void esp_sha_unlock_memory_block(void);
|
||||
|
||||
//
|
||||
/** @brief Wait for the SHA engine to finish any current operation
|
||||
*
|
||||
* @note This function does not ensure exclusive access to any SHA
|
||||
* engine. Caller should use esp_sha_try_lock_engine() and
|
||||
* esp_sha_lock_memory_block() as required.
|
||||
*
|
||||
* @note Functions declared in this header file wait for SHA engine
|
||||
* completion automatically, so you don't need to use this API for
|
||||
* these. However if accessing SHA registers directly, you will need
|
||||
* to call this before accessing SHA registers if using the
|
||||
* esp_sha_block() function.
|
||||
*
|
||||
* @note This function busy-waits, so wastes CPU resources.
|
||||
* Best to delay calling until you are about to need it.
|
||||
*
|
||||
*/
|
||||
void esp_sha_wait_idle(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -605,6 +605,14 @@ void intr_matrix_set(int cpu_no, uint32_t model_num, uint32_t intr_num);
|
|||
|
||||
#define ETS_MEM_BAR() asm volatile ( "" : : : "memory" )
|
||||
|
||||
typedef enum {
|
||||
OK = 0,
|
||||
FAIL,
|
||||
PENDING,
|
||||
BUSY,
|
||||
CANCEL,
|
||||
} STATUS;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
ROM functions for hardware SHA support.
|
||||
|
||||
It is not recommended to use these functions directly,
|
||||
use the wrapper functions in hwcrypto/sha.h instead.
|
||||
|
||||
It is not recommended to use these functions directly. If using
|
||||
them from esp-idf then use the esp_sha_lock_engine() and
|
||||
esp_sha_lock_memory_block() functions in hwcrypto/sha.h to ensure
|
||||
exclusive access.
|
||||
*/
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
|
@ -38,6 +39,8 @@ enum SHA_TYPE {
|
|||
SHA2_256,
|
||||
SHA2_384,
|
||||
SHA2_512,
|
||||
|
||||
|
||||
SHA_INVALID = -1,
|
||||
};
|
||||
|
||||
|
|
|
@ -384,7 +384,8 @@ SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t blo
|
|||
SpiFlashOpResult SPIEraseChip(void);
|
||||
|
||||
/**
|
||||
* @brief Erase a block of flash.
|
||||
* @brief Erase a 32KB block of flash
|
||||
* Uses SPI flash command 52h.
|
||||
* Please do not call this function in SDK.
|
||||
*
|
||||
* @param uint32_t block_num : Which block to erase.
|
||||
|
@ -411,6 +412,12 @@ SpiFlashOpResult SPIEraseSector(uint32_t sector_num);
|
|||
* @brief Erase some sectors.
|
||||
* Please do not call this function in SDK.
|
||||
*
|
||||
* @note If calling this function, first set
|
||||
* g_rom_flashchip.block_size = 32768; or call SPIParamCfg()
|
||||
* with appropriate parameters. This is due to a ROM bug, the
|
||||
* block erase command in use is a 32KB erase but after reset
|
||||
* the block_size field is incorrectly set to 65536.
|
||||
*
|
||||
* @param uint32_t start_addr : Start addr to erase, should be sector aligned.
|
||||
*
|
||||
* @param uint32_t area_len : Length to erase, should be sector aligned.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "esp_types.h"
|
||||
#include "esp_attr.h"
|
||||
#include "ets_sys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -51,7 +51,10 @@ static inline void cpu_write_itlb(unsigned vpn, unsigned attr)
|
|||
asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr));
|
||||
}
|
||||
|
||||
/* Make page 0 access raise an exception.
|
||||
/**
|
||||
* @brief Configure memory region protection
|
||||
*
|
||||
* Make page 0 access raise an exception.
|
||||
* Also protect some other unused pages so we can catch weirdness.
|
||||
* Useful attribute values:
|
||||
* 0 — cached, RW
|
||||
|
@ -70,9 +73,7 @@ static inline void cpu_configure_region_protection()
|
|||
cpu_write_itlb(0x20000000, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief Set CPU frequency to the value defined in menuconfig
|
||||
*
|
||||
* Called from cpu_start.c, not intended to be called from other places.
|
||||
|
@ -81,4 +82,16 @@ static inline void cpu_configure_region_protection()
|
|||
*/
|
||||
void esp_set_cpu_freq(void);
|
||||
|
||||
/**
|
||||
* @brief Stall CPU using RTC controller
|
||||
* @param cpu_id ID of the CPU to stall (0 = PRO, 1 = APP)
|
||||
*/
|
||||
void esp_cpu_stall(int cpu_id);
|
||||
|
||||
/**
|
||||
* @brief Un-stall CPU using RTC controller
|
||||
* @param cpu_id ID of the CPU to un-stall (0 = PRO, 1 = APP)
|
||||
*/
|
||||
void esp_cpu_unstall(int cpu_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -94,6 +94,16 @@
|
|||
#define DPORT_PERI_RST_EN_V 0xFFFFFFFF
|
||||
#define DPORT_PERI_RST_EN_S 0
|
||||
|
||||
/* The following bits apply to DPORT_PERI_CLK_EN_REG, DPORT_PERI_RST_EN_REG
|
||||
*/
|
||||
#define DPORT_PERI_EN_AES (1<<0)
|
||||
#define DPORT_PERI_EN_SHA (1<<1)
|
||||
#define DPORT_PERI_EN_RSA (1<<2)
|
||||
/* NB: Secure boot reset will hold SHA & AES in reset */
|
||||
#define DPORT_PERI_EN_SECUREBOOT (1<<3)
|
||||
/* NB: Digital signature reset will hold AES & RSA in reset */
|
||||
#define DPORT_PERI_EN_DIGITAL_SIGNATURE (1<<4)
|
||||
|
||||
#define DPORT_WIFI_BB_CFG_REG (DR_REG_DPORT_BASE + 0x024)
|
||||
/* DPORT_WIFI_BB_CFG : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
|
||||
/*description: */
|
||||
|
|
60
components/esp32/include/soc/hwcrypto_reg.h
Normal file
60
components/esp32/include/soc/hwcrypto_reg.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
// 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 __HWCRYPTO_REG_H__
|
||||
#define __HWCRYPTO_REG_H__
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
/* registers for RSA acceleration via Multiple Precision Integer ops */
|
||||
#define RSA_MEM_M_BLOCK_BASE ((DR_REG_RSA_BASE)+0x000)
|
||||
/* RB & Z use the same memory block, depending on phase of operation */
|
||||
#define RSA_MEM_RB_BLOCK_BASE ((DR_REG_RSA_BASE)+0x200)
|
||||
#define RSA_MEM_Z_BLOCK_BASE ((DR_REG_RSA_BASE)+0x200)
|
||||
#define RSA_MEM_Y_BLOCK_BASE ((DR_REG_RSA_BASE)+0x400)
|
||||
#define RSA_MEM_X_BLOCK_BASE ((DR_REG_RSA_BASE)+0x600)
|
||||
|
||||
#define RSA_M_DASH_REG (DR_REG_RSA_BASE + 0x800)
|
||||
#define RSA_MODEXP_MODE_REG (DR_REG_RSA_BASE + 0x804)
|
||||
#define RSA_START_MODEXP_REG (DR_REG_RSA_BASE + 0x808)
|
||||
#define RSA_MULT_MODE_REG (DR_REG_RSA_BASE + 0x80c)
|
||||
#define RSA_MULT_START_REG (DR_REG_RSA_BASE + 0x810)
|
||||
|
||||
#define RSA_INTERRUPT_REG (DR_REG_RSA_BASE + 0x814)
|
||||
|
||||
#define RSA_CLEAN_REG (DR_REG_RSA_BASE + 0x818)
|
||||
|
||||
/* SHA acceleration registers */
|
||||
#define SHA_TEXT_BASE ((DR_REG_SHA_BASE) + 0x00)
|
||||
|
||||
#define SHA_1_START_REG ((DR_REG_SHA_BASE) + 0x80)
|
||||
#define SHA_1_CONTINUE_REG ((DR_REG_SHA_BASE) + 0x84)
|
||||
#define SHA_1_LOAD_REG ((DR_REG_SHA_BASE) + 0x88)
|
||||
#define SHA_1_BUSY_REG ((DR_REG_SHA_BASE) + 0x8c)
|
||||
|
||||
#define SHA_256_START_REG ((DR_REG_SHA_BASE) + 0x90)
|
||||
#define SHA_256_CONTINUE_REG ((DR_REG_SHA_BASE) + 0x94)
|
||||
#define SHA_256_LOAD_REG ((DR_REG_SHA_BASE) + 0x98)
|
||||
#define SHA_256_BUSY_REG ((DR_REG_SHA_BASE) + 0x9c)
|
||||
|
||||
#define SHA_384_START_REG ((DR_REG_SHA_BASE) + 0xa0)
|
||||
#define SHA_384_CONTINUE_REG ((DR_REG_SHA_BASE) + 0xa4)
|
||||
#define SHA_384_LOAD_REG ((DR_REG_SHA_BASE) + 0xa8)
|
||||
#define SHA_384_BUSY_REG ((DR_REG_SHA_BASE) + 0xac)
|
||||
|
||||
#define SHA_512_START_REG ((DR_REG_SHA_BASE) + 0xb0)
|
||||
#define SHA_512_CONTINUE_REG ((DR_REG_SHA_BASE) + 0xb4)
|
||||
#define SHA_512_LOAD_REG ((DR_REG_SHA_BASE) + 0xb8)
|
||||
#define SHA_512_BUSY_REG ((DR_REG_SHA_BASE) + 0xbc)
|
||||
|
||||
#endif
|
|
@ -1319,6 +1319,36 @@
|
|||
#define PCNT_CORE_STATUS_U0_M ((PCNT_CORE_STATUS_U0_V)<<(PCNT_CORE_STATUS_U0_S))
|
||||
#define PCNT_CORE_STATUS_U0_V 0xFFFFFFFF
|
||||
#define PCNT_CORE_STATUS_U0_S 0
|
||||
/*0: positive value to zero; 1: negative value to zero; 2: counter value negative ; 3: counter value positive*/
|
||||
#define PCNT_STATUS_CNT_MODE 0x3
|
||||
#define PCNT_STATUS_CNT_MODE_M ((PCNT_STATUS_CNT_MODE_V)<<(PCNT_STATUS_CNT_MODE_S))
|
||||
#define PCNT_STATUS_CNT_MODE_V 0x3
|
||||
#define PCNT_STATUS_CNT_MODE_S 0
|
||||
/* counter value equals to thresh1*/
|
||||
#define PCNT_STATUS_THRES1 BIT(2)
|
||||
#define PCNT_STATUS_THRES1_M BIT(2)
|
||||
#define PCNT_STATUS_THRES1_V 0x1
|
||||
#define PCNT_STATUS_THRES1_S 2
|
||||
/* counter value equals to thresh0*/
|
||||
#define PCNT_STATUS_THRES0 BIT(3)
|
||||
#define PCNT_STATUS_THRES0_M BIT(3)
|
||||
#define PCNT_STATUS_THRES0_V 0x1
|
||||
#define PCNT_STATUS_THRES0_S 3
|
||||
/* counter value reaches h_lim*/
|
||||
#define PCNT_STATUS_L_LIM BIT(4)
|
||||
#define PCNT_STATUS_L_LIM_M BIT(4)
|
||||
#define PCNT_STATUS_L_LIM_V 0x1
|
||||
#define PCNT_STATUS_L_LIM_S 4
|
||||
/* counter value reaches l_lim*/
|
||||
#define PCNT_STATUS_H_LIM BIT(5)
|
||||
#define PCNT_STATUS_H_LIM_M BIT(5)
|
||||
#define PCNT_STATUS_H_LIM_V 0x1
|
||||
#define PCNT_STATUS_H_LIM_S 5
|
||||
/* counter value equals to zero*/
|
||||
#define PCNT_STATUS_ZERO BIT(6)
|
||||
#define PCNT_STATUS_ZERO_M BIT(6)
|
||||
#define PCNT_STATUS_ZERO_V 0x1
|
||||
#define PCNT_STATUS_ZERO_S 6
|
||||
|
||||
#define PCNT_U1_STATUS_REG (DR_REG_PCNT_BASE + 0x0094)
|
||||
/* PCNT_CORE_STATUS_U1 : RO ;bitpos:[31:0] ;default: 32'h0 ; */
|
||||
|
|
|
@ -113,7 +113,18 @@ typedef volatile struct {
|
|||
};
|
||||
uint32_t val;
|
||||
} int_clr;
|
||||
uint32_t status_unit[8];
|
||||
union {
|
||||
struct {
|
||||
uint32_t cnt_mode:2; /*0: positive value to zero; 1: negative value to zero; 2: counter value negative ; 3: counter value positive*/
|
||||
uint32_t thres1_lat:1; /* counter value equals to thresh1*/
|
||||
uint32_t thres0_lat:1; /* counter value equals to thresh0*/
|
||||
uint32_t l_lim_lat:1; /* counter value reaches h_lim*/
|
||||
uint32_t h_lim_lat:1; /* counter value reaches l_lim*/
|
||||
uint32_t zero_lat:1; /* counter value equals zero*/
|
||||
uint32_t reserved7:25;
|
||||
};
|
||||
uint32_t val;
|
||||
} status_unit[8];
|
||||
union {
|
||||
struct {
|
||||
uint32_t cnt_rst_u0: 1; /*Set this bit to clear unit0's counter.*/
|
||||
|
|
|
@ -2163,7 +2163,8 @@
|
|||
#define RMT_DATE_V 0xFFFFFFFF
|
||||
#define RMT_DATE_S 0
|
||||
|
||||
|
||||
/* RMT memory block address */
|
||||
#define RMT_CHANNEL_MEM(i) (DR_REG_RMT_BASE + 0x800 + 64 * 4 * (i))
|
||||
|
||||
|
||||
#endif /*_SOC_RMT_REG_H_ */
|
||||
|
|
|
@ -226,18 +226,35 @@ typedef volatile struct {
|
|||
} rmt_dev_t;
|
||||
extern rmt_dev_t RMT;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data[8]
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_item32_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint16_t duration :15;
|
||||
uint16_t level :1;
|
||||
};
|
||||
uint16_t val;
|
||||
};
|
||||
} rmt_item16_t;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data32[8]
|
||||
typedef volatile struct {
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0: 15;
|
||||
uint32_t level0: 1;
|
||||
uint32_t duration1: 15;
|
||||
uint32_t level1: 1;
|
||||
};
|
||||
uint32_t val;
|
||||
} data[64];
|
||||
rmt_item32_t data32[64];
|
||||
rmt_item16_t data16[128];
|
||||
};
|
||||
} chan[8];
|
||||
} rmt_mem_t;
|
||||
extern rmt_mem_t RMTMEM;
|
||||
|
|
|
@ -129,10 +129,10 @@
|
|||
//}}
|
||||
|
||||
//Periheral Clock {{
|
||||
#define APB_CLK_FREQ_ROM 26*1000000
|
||||
#define APB_CLK_FREQ_ROM ( 26*1000000 )
|
||||
#define CPU_CLK_FREQ_ROM APB_CLK_FREQ_ROM
|
||||
#define CPU_CLK_FREQ APB_CLK_FREQ
|
||||
#define APB_CLK_FREQ 80*1000000 //unit: Hz
|
||||
#define APB_CLK_FREQ ( 80*1000000 ) //unit: Hz
|
||||
#define UART_CLK_FREQ APB_CLK_FREQ
|
||||
#define WDT_CLK_FREQ APB_CLK_FREQ
|
||||
#define TIMER_CLK_FREQ (80000000>>4) //80MHz divided by 16
|
||||
|
@ -141,6 +141,8 @@
|
|||
//}}
|
||||
|
||||
#define DR_REG_DPORT_BASE 0x3ff00000
|
||||
#define DR_REG_RSA_BASE 0x3ff02000
|
||||
#define DR_REG_SHA_BASE 0x3ff03000
|
||||
#define DR_REG_UART_BASE 0x3ff40000
|
||||
#define DR_REG_SPI1_BASE 0x3ff42000
|
||||
#define DR_REG_SPI0_BASE 0x3ff43000
|
||||
|
|
18
components/esp32/include/soc/wdev_reg.h
Normal file
18
components/esp32/include/soc/wdev_reg.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2010-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
|
||||
|
||||
/* Hardware random number generator register */
|
||||
#define WDEV_RND_REG 0x60035144
|
|
@ -42,7 +42,7 @@
|
|||
* share the name with the existing functions from hal.h.
|
||||
* Including this header file will define XTHAL_USE_CACHE_MACROS
|
||||
* which directs hal.h not to use the functions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Single-cache-line operations in C-callable inline assembly.
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "esp_freertos_hooks.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "driver/timer.h"
|
||||
|
||||
#include "esp_int_wdt.h"
|
||||
|
||||
|
@ -85,7 +86,7 @@ void esp_int_wdt_init() {
|
|||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
TIMERG1.int_clr_timers.wdt=1;
|
||||
TIMERG1.int_ena.wdt=1;
|
||||
timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M);
|
||||
esp_register_freertos_tick_hook(tick_hook);
|
||||
ESP_INTR_DISABLE(WDT_INT_NUM);
|
||||
intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3ee7a22306abf73aa4d270f566b273929de98d60
|
||||
Subproject commit 1ef5197246db363681ca78c1e3edc2d2cca92bbe
|
124
components/esp32/lib_printf.c
Normal file
124
components/esp32/lib_printf.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright 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.
|
||||
|
||||
/**
|
||||
* @file lib_printf.c
|
||||
*
|
||||
* This file contains library-specific printf functions
|
||||
* used by WiFi libraries in the `lib` directory.
|
||||
* These function are used to catch any output which gets printed
|
||||
* by libraries, and redirect it to ESP_LOG macros.
|
||||
*
|
||||
* Eventually WiFi libraries will use ESP_LOG functions internally
|
||||
* and these definitions will be removed.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#define VPRINTF_STACK_BUFFER_SIZE 80
|
||||
|
||||
static int lib_printf(const char* tag, const char* format, va_list arg)
|
||||
{
|
||||
char temp[VPRINTF_STACK_BUFFER_SIZE];
|
||||
int len = vsnprintf(temp, sizeof(temp) - 1, format, arg);
|
||||
temp[sizeof(temp) - 1] = 0;
|
||||
int i;
|
||||
for (i = len - 1; i >= 0; --i) {
|
||||
if (temp[i] != '\n' && temp[i] != '\r' && temp[i] != ' ') {
|
||||
break;
|
||||
}
|
||||
temp[i] = 0;
|
||||
}
|
||||
if (i > 0) {
|
||||
ESP_EARLY_LOGI(tag, "%s", temp);
|
||||
}
|
||||
va_end(arg);
|
||||
return len;
|
||||
}
|
||||
|
||||
int phy_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("phy", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int rtc_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("rtc", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int wpa_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("wpa", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int wps_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("wps", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int pp_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("pp", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int sc_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("smartconfig", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int core_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("core", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int net80211_printf(const char* format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
int res = lib_printf("net80211", format, arg);
|
||||
va_end(arg);
|
||||
return res;
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/cpu.h"
|
||||
|
||||
#include "esp_gdbstub.h"
|
||||
#include "esp_panic.h"
|
||||
|
@ -108,21 +109,10 @@ static const char *edesc[]={
|
|||
void commonErrorHandler(XtExcFrame *frame);
|
||||
|
||||
//The fact that we've panic'ed probably means the other CPU is now running wild, possibly
|
||||
//messing up the serial output, so we kill it here.
|
||||
static void haltOtherCore() {
|
||||
if (xPortGetCoreID()==0) {
|
||||
//Kill app cpu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
|
||||
} else {
|
||||
//Kill pro cpu
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C1_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
|
||||
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
|
||||
}
|
||||
//messing up the serial output, so we stall it here.
|
||||
static void haltOtherCore()
|
||||
{
|
||||
esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
|
||||
}
|
||||
|
||||
//Returns true when a debugger is attached using JTAG.
|
||||
|
|
|
@ -179,7 +179,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle,
|
|||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
esp_efuse_read_mac(sta_mac);
|
||||
if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) {
|
||||
ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \
|
||||
MACSTR ", found " MACSTR,
|
||||
|
@ -210,7 +210,7 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
|
|||
return err;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
esp_efuse_read_mac(sta_mac);
|
||||
err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
|
|
142
components/esp32/rtc.h
Normal file
142
components/esp32/rtc.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* @file rtc.h
|
||||
* @brief Declarations of APIs provided by librtc.a
|
||||
*
|
||||
* This file is not in the include directory of esp32 component, so it is not
|
||||
* part of the public API. As the source code of librtc.a is gradually moved
|
||||
* into the ESP-IDF, some of these APIs will be exposed to applications.
|
||||
*
|
||||
* For now, only esp_deep_sleep function declared in esp_deepsleep.h
|
||||
* is part of public API.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "soc/soc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum{
|
||||
XTAL_40M = 40,
|
||||
XTAL_26M = 26,
|
||||
XTAL_24M = 24,
|
||||
XTAL_AUTO = 0
|
||||
} xtal_freq_t;
|
||||
|
||||
typedef enum{
|
||||
CPU_XTAL = 0,
|
||||
CPU_80M = 1,
|
||||
CPU_160M = 2,
|
||||
CPU_240M = 3,
|
||||
CPU_2M = 4
|
||||
} cpu_freq_t;
|
||||
|
||||
typedef enum {
|
||||
CALI_RTC_MUX = 0,
|
||||
CALI_8MD256 = 1,
|
||||
CALI_32K_XTAL = 2
|
||||
} cali_clk_t;
|
||||
|
||||
/**
|
||||
* This function must be called to initialize RTC library
|
||||
* @param xtal_freq Frequency of main crystal
|
||||
*/
|
||||
void rtc_init_lite(xtal_freq_t xtal_freq);
|
||||
|
||||
/**
|
||||
* Switch CPU frequency
|
||||
* @param cpu_freq new CPU frequency
|
||||
*/
|
||||
void rtc_set_cpu_freq(cpu_freq_t cpu_freq);
|
||||
|
||||
/**
|
||||
* @brief Return RTC slow clock's period
|
||||
* @param cali_clk clock to calibrate
|
||||
* @param slow_clk_cycles number of slow clock cycles to average
|
||||
* @param xtal_freq chip's main XTAL freq
|
||||
* @return average slow clock period in microseconds, Q13.19 fixed point format
|
||||
*/
|
||||
uint32_t rtc_slowck_cali(cali_clk_t cali_clk, uint32_t slow_clk_cycles);
|
||||
|
||||
/**
|
||||
* @brief Convert from microseconds to slow clock cycles
|
||||
* @param time_in_us_h Time in microseconds, higher 32 bit part
|
||||
* @param time_in_us_l Time in microseconds, lower 32 bit part
|
||||
* @param slow_clk_period Period of slow clock in microseconds, Q13.19 fixed point format (as returned by rtc_slowck_cali).
|
||||
* @param[out] cylces_h output, higher 32 bit part of number of slow clock cycles
|
||||
* @param[out] cycles_l output, lower 32 bit part of number of slow clock cycles
|
||||
*/
|
||||
void rtc_usec2rtc(uint32_t time_in_us_h, uint32_t time_in_us_l, uint32_t slow_clk_period, uint32_t *cylces_h, uint32_t *cycles_l);
|
||||
|
||||
|
||||
#define DEEP_SLEEP_PD_NORMAL BIT(0) /*!< Base deep sleep mode */
|
||||
#define DEEP_SLEEP_PD_RTC_PERIPH BIT(1) /*!< Power down RTC peripherals */
|
||||
#define DEEP_SLEEP_PD_RTC_SLOW_MEM BIT(2) /*!< Power down RTC SLOW memory */
|
||||
#define DEEP_SLEEP_PD_RTC_FAST_MEM BIT(3) /*!< Power down RTC FAST memory */
|
||||
|
||||
/**
|
||||
* @brief Prepare for entering sleep mode
|
||||
* @param deep_slp DEEP_SLEEP_PD_ flags combined with OR (DEEP_SLEEP_PD_NORMAL must be included)
|
||||
* @param cpu_lp_mode for deep sleep, should be 0
|
||||
*/
|
||||
void rtc_slp_prep_lite(uint32_t deep_slp, uint32_t cpu_lp_mode);
|
||||
|
||||
|
||||
#define RTC_EXT_EVENT0_TRIG BIT(0)
|
||||
#define RTC_EXT_EVENT1_TRIG BIT(1)
|
||||
#define RTC_GPIO_TRIG BIT(2)
|
||||
#define RTC_TIMER_EXPIRE BIT(3)
|
||||
#define RTC_SDIO_TRIG BIT(4)
|
||||
#define RTC_MAC_TRIG BIT(5)
|
||||
#define RTC_UART0_TRIG BIT(6)
|
||||
#define RTC_UART1_TRIG BIT(7)
|
||||
#define RTC_TOUCH_TRIG BIT(8)
|
||||
#define RTC_SAR_TRIG BIT(9)
|
||||
#define RTC_BT_TRIG BIT(10)
|
||||
|
||||
|
||||
#define RTC_EXT_EVENT0_TRIG_EN RTC_EXT_EVENT0_TRIG
|
||||
#define RTC_EXT_EVENT1_TRIG_EN RTC_EXT_EVENT1_TRIG
|
||||
#define RTC_GPIO_TRIG_EN RTC_GPIO_TRIG
|
||||
#define RTC_TIMER_EXPIRE_EN RTC_TIMER_EXPIRE
|
||||
#define RTC_SDIO_TRIG_EN RTC_SDIO_TRIG
|
||||
#define RTC_MAC_TRIG_EN RTC_MAC_TRIG
|
||||
#define RTC_UART0_TRIG_EN RTC_UART0_TRIG
|
||||
#define RTC_UART1_TRIG_EN RTC_UART1_TRIG
|
||||
#define RTC_TOUCH_TRIG_EN RTC_TOUCH_TRIG
|
||||
#define RTC_SAR_TRIG_EN RTC_SAR_TRIG
|
||||
#define RTC_BT_TRIG_EN RTC_BT_TRIG
|
||||
|
||||
/**
|
||||
* @brief Enter sleep mode for given number of cycles
|
||||
* @param cycles_h higher 32 bit part of number of slow clock cycles
|
||||
* @param cycles_l lower 32 bit part of number of slow clock cycles
|
||||
* @param wakeup_opt wake up reason to enable (RTC_xxx_EN flags combined with OR)
|
||||
* @param reject_opt reserved, should be 0
|
||||
* @return TBD
|
||||
*/
|
||||
uint32_t rtc_sleep(uint32_t cycles_h, uint32_t cycles_l, uint32_t wakeup_opt, uint32_t reject_opt);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
158
components/esp32/system_api.c
Normal file
158
components/esp32/system_api.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
// Copyright 2013-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.
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_internal.h"
|
||||
#include "esp_log.h"
|
||||
#include "rom/efuse.h"
|
||||
#include "rom/cache.h"
|
||||
#include "rom/uart.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
static const char* TAG = "system_api";
|
||||
|
||||
void system_init()
|
||||
{
|
||||
}
|
||||
|
||||
esp_err_t esp_efuse_read_mac(uint8_t* mac)
|
||||
{
|
||||
uint8_t efuse_crc;
|
||||
uint8_t calc_crc;
|
||||
uint32_t mac_low = REG_READ(EFUSE_BLK0_RDATA1_REG);
|
||||
uint32_t mac_high = REG_READ(EFUSE_BLK0_RDATA2_REG);
|
||||
|
||||
mac[0] = mac_high >> 8;
|
||||
mac[1] = mac_high;
|
||||
mac[2] = mac_low >> 24;
|
||||
mac[3] = mac_low >> 16;
|
||||
mac[4] = mac_low >> 8;
|
||||
mac[5] = mac_low;
|
||||
|
||||
efuse_crc = mac_high >> 16;
|
||||
calc_crc = esp_crc8(mac, 6);
|
||||
|
||||
if (efuse_crc != calc_crc) {
|
||||
// Small range of MAC addresses are accepted even if CRC is invalid.
|
||||
// These addresses are reserved for Espressif internal use.
|
||||
if ((mac_high & 0xFFFF) == 0x18fe) {
|
||||
if ((mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "MAC address CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__((alias("esp_efuse_read_mac")));
|
||||
|
||||
|
||||
void IRAM_ATTR esp_restart(void)
|
||||
{
|
||||
esp_wifi_stop();
|
||||
|
||||
// Disable scheduler on this core.
|
||||
vTaskSuspendAll();
|
||||
const uint32_t core_id = xPortGetCoreID();
|
||||
const uint32_t other_core_id = core_id == 0 ? 1 : 0;
|
||||
esp_cpu_stall(other_core_id);
|
||||
|
||||
// We need to disable TG0/TG1 watchdogs
|
||||
// First enable RTC watchdog to be on the safe side
|
||||
REG_WRITE(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
|
||||
REG_WRITE(RTC_CNTL_WDTCONFIG0_REG,
|
||||
RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M |
|
||||
(1 << RTC_CNTL_WDT_SYS_RESET_LENGTH_S) |
|
||||
(1 << RTC_CNTL_WDT_CPU_RESET_LENGTH_S) );
|
||||
REG_WRITE(RTC_CNTL_WDTCONFIG1_REG, 128000);
|
||||
|
||||
// Disable TG0/TG1 watchdogs
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_config0.en = 0;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en = 0;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
|
||||
// Disable all interrupts
|
||||
xt_ints_off(0xFFFFFFFF);
|
||||
|
||||
// Disable cache
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Read_Disable(1);
|
||||
|
||||
// Flush any data left in UART FIFO
|
||||
uart_tx_flush(0);
|
||||
uart_tx_flush(1);
|
||||
uart_tx_flush(2);
|
||||
|
||||
// Reset wifi/bluetooth (bb/mac)
|
||||
SET_PERI_REG_MASK(DPORT_WIFI_RST_EN_REG, 0x1f);
|
||||
REG_WRITE(DPORT_WIFI_RST_EN_REG, 0);
|
||||
|
||||
// Reset timer/spi/uart
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,
|
||||
DPORT_TIMERS_RST | DPORT_SPI_RST_1 | DPORT_UART_RST);
|
||||
REG_WRITE(DPORT_PERIP_RST_EN_REG, 0);
|
||||
|
||||
// Reset CPUs
|
||||
if (core_id == 0) {
|
||||
// Running on PRO CPU: APP CPU is stalled. Can reset both CPUs.
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
|
||||
RTC_CNTL_SW_PROCPU_RST_M | RTC_CNTL_SW_APPCPU_RST_M);
|
||||
} else {
|
||||
// Running on APP CPU: need to reset PRO CPU and unstall it,
|
||||
// then stall APP CPU
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST_M);
|
||||
esp_cpu_unstall(0);
|
||||
esp_cpu_stall(1);
|
||||
}
|
||||
while(true) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void system_restart(void) __attribute__((alias("esp_restart")));
|
||||
|
||||
void system_restore(void)
|
||||
{
|
||||
esp_wifi_restore();
|
||||
}
|
||||
|
||||
uint32_t esp_get_free_heap_size(void)
|
||||
{
|
||||
return xPortGetFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t system_get_free_heap_size(void) __attribute__((alias("esp_get_free_heap_size")));
|
||||
|
||||
const char* system_get_sdk_version(void)
|
||||
{
|
||||
return "master";
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/timer.h"
|
||||
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
|
@ -204,7 +205,7 @@ void esp_task_wdt_init() {
|
|||
intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
|
||||
xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
|
||||
TIMERG0.int_clr_timers.wdt=1;
|
||||
TIMERG0.int_ena.wdt=1;
|
||||
timer_group_intr_enable(TIMER_GROUP_0, TIMG_WDT_INT_ENA_M);
|
||||
ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
|
||||
}
|
||||
|
||||
|
|
17
components/esp32/test/component.mk
Normal file
17
components/esp32/test/component.mk
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
|
||||
COMPONENT_SRCDIRS := . test_vectors
|
||||
|
||||
include $(IDF_PATH)/make/component_common.mk
|
||||
|
||||
test_tjpgd.o: test_tjpgd_logo.h
|
||||
|
||||
test_tjpgd_logo.h: $(COMPONENT_PATH)/logo.jpg
|
||||
$(summary) XXD logo.jpg
|
||||
$(Q) cd $(COMPONENT_PATH); xxd -i logo.jpg $(COMPONENT_BUILD_DIR)/test_tjpgd_logo.h
|
BIN
components/esp32/test/logo.jpg
Normal file
BIN
components/esp32/test/logo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
293
components/esp32/test/test_ahb_arb.c
Normal file
293
components/esp32/test/test_ahb_arb.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
|
||||
/*
|
||||
This test tests the s32c1i instruction when the AHB bus is also used. To create some AHB traffic, we use the I2S interface
|
||||
to copy bytes over from one memory location to another. DO NOT USE the i2s routines inhere, they've been trial-and-error'ed until
|
||||
the point where they happened to do what I want.
|
||||
*/
|
||||
|
||||
static void lcdIfaceInit()
|
||||
{
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
}
|
||||
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
static void finishDma()
|
||||
{
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is a very, very, very hacked up LCD routine which ends up basically doing a memcpy from sbuf to rbuf.
|
||||
*/
|
||||
static void sendRecvBufDma(uint16_t *sbuf, uint16_t *rbuf, int len)
|
||||
{
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len * 2;
|
||||
dmaDesc[0].size = len * 2;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)sbuf;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len * 2;
|
||||
dmaDesc[1].size = len * 2;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)rbuf;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
#define DMALEN (2048-2)
|
||||
|
||||
static void tskLcd(void *pvParameters)
|
||||
{
|
||||
uint16_t *sbuf = malloc(DMALEN * 2);
|
||||
uint16_t *rbuf = malloc(DMALEN * 2);
|
||||
uint16_t xorval = 0;
|
||||
int x;
|
||||
lcdIfaceInit();
|
||||
// lcdFlush();
|
||||
while (1) {
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
sbuf[x] = x ^ xorval;
|
||||
}
|
||||
for (x = 0; x < DMALEN; x++) {
|
||||
rbuf[x] = 0; //clear rbuf
|
||||
}
|
||||
sendRecvBufDma(sbuf, rbuf, DMALEN);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
finishDma();
|
||||
for (x = 0; x < DMALEN; x++) if (rbuf[x] != (x ^ xorval)) {
|
||||
printf("Rxbuf err! pos %d val %x xor %x", x, (int)rbuf[x], (int)xorval);
|
||||
}
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
xorval++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void test_s32c1i_lock(volatile int *lockvar, int lockval, int unlockval, volatile int *ctr);
|
||||
|
||||
static volatile int ctr = 0, state = 0;
|
||||
static volatile int lock = 0;
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int err = 0, run = 0;
|
||||
while (1) {
|
||||
ctr = 0; lock = 0;
|
||||
state = 1;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock(&lock, 1, 0, &ctr);
|
||||
}
|
||||
vTaskDelay(60 / portTICK_PERIOD_MS);
|
||||
state = 2;
|
||||
if (ctr != 16 * 1024 * 2) {
|
||||
printf("Lock malfunction detected! Ctr=0x%x instead of %x\n", ctr, 16 * 1024 * 2);
|
||||
err++;
|
||||
}
|
||||
run++;
|
||||
printf("Run %d err %d\n", run, err);
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_s32c1i_lock;
|
||||
void (*test_s32c1i_lock2)(volatile int * lockvar, int lockval, int unlockval, volatile int * ctr) = (void *)FB2ADDR;
|
||||
volatile int w;
|
||||
int delay;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++; //copy routine to different pool
|
||||
}
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 0; x < 16 * 1024; x++) {
|
||||
test_s32c1i_lock2(&lock, 2, 0, &ctr);
|
||||
//Some random delay to increase chance of weirdness
|
||||
if ((x & 0x1f) == 0) {
|
||||
delay = rand() & 0x1f;
|
||||
for (w = 0; w < delay; w++);
|
||||
}
|
||||
}
|
||||
while (state != 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw]")
|
||||
{
|
||||
int i;
|
||||
TaskHandle_t th[3];
|
||||
state = 0;
|
||||
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskLcd , "tsklcd" , 2048, NULL, 3, &th[2], 0);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 3; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
}
|
||||
|
51
components/esp32/test/test_ahb_arb_asm.S
Normal file
51
components/esp32/test/test_ahb_arb_asm.S
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_s32c1i_lock
|
||||
.type test_s32c1i_lock,@function
|
||||
//Args:
|
||||
//a2 - lock addr
|
||||
//a3 - val to lock with
|
||||
//a4 - val to unlock with
|
||||
//a5 - addr to increase
|
||||
test_s32c1i_lock:
|
||||
entry a1, 64
|
||||
wsr a4, SCOMPARE1
|
||||
lockloop:
|
||||
mov a6, a3
|
||||
s32c1i a6, a2, 0
|
||||
bne a4, a6, lockloop
|
||||
|
||||
l32i a6, a5, 0
|
||||
//Give other CPU the time to mess up the inc if the lock somehow malfunctions
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
addi a6, a6, 1
|
||||
s32i a6, a5, 0
|
||||
|
||||
|
||||
//No need to actually let this loop but hey, a hang indicates an error, right?
|
||||
wsr a3, SCOMPARE1
|
||||
unlockloop:
|
||||
mov a6, a4
|
||||
s32c1i a6, a2, 0
|
||||
bne a3, a6, unlockloop
|
||||
|
||||
retw
|
132
components/esp32/test/test_fastbus.c
Normal file
132
components/esp32/test/test_fastbus.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
/*
|
||||
This test tests the 'fast' peripherial bus at 0x3ff40000. This bus is connected directly to the core, and as such
|
||||
can receive 'speculative' reads, that is, reads that may or may not actually be executed in the code flow. This
|
||||
may mess with any FIFOs mapped in the region: if a byte gets dropped due to a missed speculative read, the fifo
|
||||
may advance to the next byte anyway.
|
||||
|
||||
This code tests reading/writing from the UART1 FIFO, using both cores. For this to work, it's required that the
|
||||
UARTs RX and TX lines are connected.
|
||||
*/
|
||||
|
||||
|
||||
void test_fastbus_cp(int fifo_addr, unsigned char *buf, int len, int *dummy);
|
||||
|
||||
static volatile int state = 0;
|
||||
static volatile int xor = 0;
|
||||
static unsigned char res[128];
|
||||
|
||||
static void tskOne(void *pvParameters)
|
||||
{
|
||||
int run = 0, err = 0;
|
||||
int x;
|
||||
int ct[256];
|
||||
volatile int w;
|
||||
int dummy;
|
||||
while (1) {
|
||||
state = 1;
|
||||
for (x = 0; x < 64; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
for (w = 0; w < (1 << 14); w++); //delay
|
||||
state = 2;
|
||||
test_fastbus_cp(UART_FIFO_REG(1), &res[0], 64, &dummy);
|
||||
for (w = 0; w < (1 << 10); w++); //delay
|
||||
for (x = 0; x < 255; x++) {
|
||||
ct[x] = 0; //zero ctrs
|
||||
}
|
||||
for (x = 0; x < 128; x++) {
|
||||
ct[(int)res[x]^xor]++; //count values
|
||||
}
|
||||
for (x = 0; x < 255; x++) { //check counts
|
||||
if (ct[x] != (x < 128 ? 1 : 0)) {
|
||||
//Disregard first few loops; there may be crap in the fifo.
|
||||
if (run > 2) {
|
||||
err++;
|
||||
printf("Error! Received value %d %d times!\n", x, ct[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
run++;
|
||||
if ((run & 255) == 0) {
|
||||
printf("Loop %d errct %d\n", run, err);
|
||||
}
|
||||
xor = (xor + 1) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
#define FB2ADDR 0x40098000
|
||||
|
||||
static void tskTwo(void *pvParameters)
|
||||
{
|
||||
int x;
|
||||
int dummy;
|
||||
int *p = (int *)FB2ADDR;
|
||||
int *s = (int *)test_fastbus_cp;
|
||||
for (x = 0; x < 100; x++) {
|
||||
*p++ = *s++;
|
||||
}
|
||||
void (*test_fastbus_cp2)(int fifo_addr, unsigned char * buf, int len, int * dummy) = (void *)FB2ADDR;
|
||||
|
||||
|
||||
while (1) {
|
||||
while (state != 1) ;
|
||||
for (x = 64; x < 128; x++) {
|
||||
WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
|
||||
}
|
||||
while (state != 2);
|
||||
test_fastbus_cp2(UART_FIFO_REG(1), &res[64], 64, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Fast I/O bus test", "[hw]")
|
||||
{
|
||||
int i;
|
||||
if ((REG_UART_BASE(0) >> 16) != 0x3ff4) {
|
||||
printf("Error! Uart base isn't on fast bus.\n");
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_SD_DATA3_U);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, FUNC_SD_DATA2_U1RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_U1TXD);
|
||||
|
||||
int reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
|
||||
WRITE_PERI_REG(UART_CONF1_REG(1), reg_val);
|
||||
WRITE_PERI_REG(UART_CLKDIV_REG(1), 0x30); //semi-random
|
||||
// CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(1), UART_TXFIFO_EMPTY_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
|
||||
|
||||
TaskHandle_t th[2];
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskOne , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskTwo , "tsktwo" , 2048, NULL, 3, &th[1], 1);
|
||||
|
||||
// Let stuff run for 20s
|
||||
while (1) {
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 2; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
xt_ints_off(1 << ETS_UART0_INUM);
|
||||
}
|
||||
|
32
components/esp32/test/test_fastbus_asm.S
Normal file
32
components/esp32/test/test_fastbus_asm.S
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
This little bit of code is executed in-place by one CPU, but copied to a different memory region
|
||||
by the other CPU. Make sure it stays position-independent.
|
||||
*/
|
||||
.text
|
||||
.align 4
|
||||
.global test_fastbus_cp
|
||||
.type test_fastbus_cp,@function
|
||||
//Args:
|
||||
//a2 - fifo addr
|
||||
//a3 - buf addr
|
||||
//a4 - len
|
||||
//a5 - ptr to int to use
|
||||
test_fastbus_cp:
|
||||
entry a1,64
|
||||
back:
|
||||
beqi a4, 0, out //check if loop done
|
||||
s32i a4, a5, 0 //store value, for shits and/or giggles
|
||||
memw //make sure write happens
|
||||
l32i a4, a5, 0 //load value again, to thwart any prediction in the pipeline
|
||||
bbsi a4, 0, pred //Random jump to check predictive reads. Both branches should do the same.
|
||||
l32i a6, a2, 0 //read from fifo 1
|
||||
j predout
|
||||
pred:
|
||||
l32i a6, a2, 0 //read from fifo 2
|
||||
predout:
|
||||
s8i a6, a3, 0 //store result
|
||||
addi a3, a3, 1 //inc ptr
|
||||
addi a4, a4, -1 //next
|
||||
j back //loop again
|
||||
out:
|
||||
retw //and we are done
|
193
components/esp32/test/test_fp.c
Normal file
193
components/esp32/test/test_fp.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
|
||||
static float addsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"add.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float mulsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"mul.s f2, f0, f1\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float divsf(float a, float b)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"wfr f1, %2\n"
|
||||
"div0.s f3, f1 \n"
|
||||
"nexp01.s f4, f1 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5, f4, f3 \n"
|
||||
"mov.s f6, f3 \n"
|
||||
"mov.s f7, f1 \n"
|
||||
"nexp01.s f8, f0 \n"
|
||||
"maddn.s f6, f5, f3 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"const.s f2, 0 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2, f0, f3 \n"
|
||||
"mkdadj.s f7, f0 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"const.s f5, 1 \n"
|
||||
"maddn.s f5,f4,f6 \n"
|
||||
"maddn.s f2,f9,f6 \n"
|
||||
"neg.s f9, f8 \n"
|
||||
"maddn.s f6,f5,f6 \n"
|
||||
"maddn.s f9,f4,f2 \n"
|
||||
"addexpm.s f2, f7 \n"
|
||||
"addexp.s f6, f7 \n"
|
||||
"divn.s f2,f9,f6\n"
|
||||
"rfr %0, f2\n"
|
||||
:"=r"(result):"r"(a), "r"(b)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
static float sqrtsf(float a)
|
||||
{
|
||||
float result;
|
||||
asm volatile (
|
||||
"wfr f0, %1\n"
|
||||
"sqrt0.s f2, f0\n"
|
||||
"const.s f5, 0\n"
|
||||
"maddn.s f5, f2, f2\n"
|
||||
"nexp01.s f3, f0\n"
|
||||
"const.s f4, 3\n"
|
||||
"addexp.s f3, f4\n"
|
||||
"maddn.s f4, f5, f3\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"neg.s f6, f5\n"
|
||||
"maddn.s f2, f4, f2\n"
|
||||
"const.s f1, 0\n"
|
||||
"const.s f4, 0\n"
|
||||
"const.s f7, 0\n"
|
||||
"maddn.s f1, f6, f2\n"
|
||||
"maddn.s f4, f2, f3\n"
|
||||
"const.s f6, 3\n"
|
||||
"maddn.s f7, f6, f2\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"maddn.s f6, f4, f2\n"
|
||||
"neg.s f3, f7\n"
|
||||
"maddn.s f1, f5, f3\n"
|
||||
"maddn.s f7, f6, f7\n"
|
||||
"mksadj.s f2, f0\n"
|
||||
"nexp01.s f5, f0\n"
|
||||
"maddn.s f5, f1, f1\n"
|
||||
"neg.s f3, f7\n"
|
||||
"addexpm.s f1, f2\n"
|
||||
"addexp.s f3, f2\n"
|
||||
"divn.s f1, f5, f3\n"
|
||||
"rfr %0, f1\n"
|
||||
:"=r"(result):"r"(a)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_CASE("test FP add", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.5f;
|
||||
float c = addsf(a, b);
|
||||
float eps = c - 100.5f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP mul", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 0.05f;
|
||||
float c = mulsf(a, b);
|
||||
float eps = c - 5.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP div", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float b = 5.0f;
|
||||
float c = divsf(a, b);
|
||||
float eps = c - 20.0f;
|
||||
printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
TEST_CASE("test FP sqrt", "[fp]")
|
||||
{
|
||||
float a = 100.0f;
|
||||
float c = sqrtsf(a);
|
||||
float eps = c - 10.0f;
|
||||
printf("a=%g c=%g eps=%g\r\n", a, c, eps);
|
||||
TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
|
||||
}
|
||||
|
||||
|
||||
struct TestFPState {
|
||||
int fail;
|
||||
int done;
|
||||
};
|
||||
|
||||
static const int testFpIter = 100000;
|
||||
|
||||
static void tskTestFP(void *pvParameters)
|
||||
{
|
||||
struct TestFPState *state = (struct TestFPState *) pvParameters;
|
||||
for (int i = 0; i < testFpIter; ++i) {
|
||||
// calculate zero in a slightly obscure way
|
||||
float y = sqrtsf(addsf(1.0f, divsf(mulsf(sqrtsf(2), sqrtsf(2)), 2.0f)));
|
||||
y = mulsf(y, y);
|
||||
y = addsf(y, -2.0f);
|
||||
// check that result is not far from zero
|
||||
float eps = fabs(y);
|
||||
if (eps > 1e-6f) {
|
||||
state->fail++;
|
||||
printf("%s: i=%d y=%f eps=%f\r\n", __func__, i, y, eps);
|
||||
}
|
||||
}
|
||||
state->done++;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("context switch saves FP registers", "[fp]")
|
||||
{
|
||||
struct TestFPState state;
|
||||
state.done = 0;
|
||||
state.fail = 0;
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk1", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk2", 2048, &state, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk3", 2048, &state, 3, NULL, 1);
|
||||
xTaskCreatePinnedToCore(tskTestFP, "tsk4", 2048, &state, 3, NULL, 0);
|
||||
while (state.done != 4) {
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
if (state.fail) {
|
||||
const int total = testFpIter * 4;
|
||||
printf("Failed: %d, total: %d\r\n", state.fail, total);
|
||||
}
|
||||
TEST_ASSERT(state.fail == 0);
|
||||
}
|
77
components/esp32/test/test_miniz.c
Normal file
77
components/esp32/test/test_miniz.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/miniz.h"
|
||||
#include "unity.h"
|
||||
|
||||
|
||||
#define DATASIZE (1024*64)
|
||||
|
||||
TEST_CASE("Test miniz compression/decompression", "[miniz]")
|
||||
{
|
||||
int x;
|
||||
char b;
|
||||
char *inbuf, *outbuf;
|
||||
tdefl_compressor *comp;
|
||||
tinfl_decompressor *decomp;
|
||||
tdefl_status status;
|
||||
size_t inbytes = 0, outbytes = 0, inpos = 0, outpos = 0, compsz;
|
||||
printf("Allocating data buffer and filling it with semi-random data\n");
|
||||
inbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(inbuf != NULL);
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = (x & 1) ? rand() & 0xff : 0;
|
||||
}
|
||||
printf("Allocating compressor & outbuf (%d bytes)\n", sizeof(tdefl_compressor));
|
||||
comp = malloc(sizeof(tdefl_compressor));
|
||||
TEST_ASSERT(comp != NULL);
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Compressing...\n");
|
||||
status = tdefl_init(comp, NULL, NULL, TDEFL_WRITE_ZLIB_HEADER | 1500);
|
||||
TEST_ASSERT(status == TDEFL_STATUS_OKAY);
|
||||
while (inbytes != DATASIZE) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = DATASIZE - inpos;
|
||||
tdefl_compress(comp, &inbuf[inpos], &inbytes, &outbuf[outpos], &outbytes, TDEFL_FINISH);
|
||||
printf("...Compressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
compsz = outpos;
|
||||
free(comp);
|
||||
//Kill inbuffer
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
inbuf[x] = 0;
|
||||
}
|
||||
free(inbuf);
|
||||
|
||||
inbuf = outbuf;
|
||||
outbuf = malloc(DATASIZE);
|
||||
TEST_ASSERT(outbuf != NULL);
|
||||
printf("Reinflating...\n");
|
||||
decomp = malloc(sizeof(tinfl_decompressor));
|
||||
TEST_ASSERT(decomp != NULL);
|
||||
tinfl_init(decomp);
|
||||
inpos = 0; outpos = 0;
|
||||
while (inbytes != compsz) {
|
||||
outbytes = DATASIZE - outpos;
|
||||
inbytes = compsz - inpos;
|
||||
tinfl_decompress(decomp, (const mz_uint8 *)&inbuf[inpos], &inbytes, (uint8_t *)outbuf, (mz_uint8 *)&outbuf[outpos], &outbytes, TINFL_FLAG_PARSE_ZLIB_HEADER);
|
||||
printf("...Decompressed %d into %d bytes\n", inbytes, outbytes);
|
||||
inpos += inbytes; outpos += outbytes;
|
||||
}
|
||||
printf("Checking if same...\n");
|
||||
srand(0);
|
||||
for (x = 0; x < DATASIZE; x++) {
|
||||
b = (x & 1) ? rand() & 0xff : 0;
|
||||
if (outbuf[x] != b) {
|
||||
printf("Pos %x: %hhx!=%hhx\n", x, outbuf[x], b);
|
||||
TEST_ASSERT(0);
|
||||
}
|
||||
}
|
||||
printf("Great Success!\n");
|
||||
free(inbuf);
|
||||
free(outbuf);
|
||||
free(decomp);
|
||||
}
|
91
components/esp32/test/test_tjpgd.c
Normal file
91
components/esp32/test/test_tjpgd.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "rom/tjpgd.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "unity.h"
|
||||
|
||||
#include "test_tjpgd_logo.h"
|
||||
|
||||
typedef struct {
|
||||
const unsigned char *inData;
|
||||
int inPos;
|
||||
unsigned char *outData;
|
||||
int outW;
|
||||
int outH;
|
||||
} JpegDev;
|
||||
|
||||
|
||||
static UINT infunc(JDEC *decoder, BYTE *buf, UINT len)
|
||||
{
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
printf("Reading %d bytes from pos %d\n", len, jd->inPos);
|
||||
if (buf != NULL) {
|
||||
memcpy(buf, jd->inData + jd->inPos, len);
|
||||
}
|
||||
jd->inPos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
{
|
||||
unsigned char *in = (unsigned char *)bitmap;
|
||||
unsigned char *out;
|
||||
int y;
|
||||
printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right);
|
||||
JpegDev *jd = (JpegDev *)decoder->device;
|
||||
for (y = rect->top; y <= rect->bottom; y++) {
|
||||
out = jd->outData + ((jd->outW * y) + rect->left) * 3;
|
||||
memcpy(out, in, ((rect->right - rect->left) + 1) * 3);
|
||||
in += ((rect->right - rect->left) + 1) * 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define TESTW 48
|
||||
#define TESTH 48
|
||||
#define WORKSZ 3100
|
||||
|
||||
TEST_CASE("Test JPEG decompression library", "[tjpgd]")
|
||||
{
|
||||
char aapix[] = " .:;+=xX$$";
|
||||
unsigned char *decoded, *p;
|
||||
char *work;
|
||||
int r;
|
||||
int x, y, v;
|
||||
JDEC decoder;
|
||||
JpegDev jd;
|
||||
decoded = malloc(48 * 48 * 3);
|
||||
for (x = 0; x < 48 * 48 * 3; x += 2) {
|
||||
decoded[x] = 0; decoded[x + 1] = 0xff;
|
||||
}
|
||||
work = malloc(WORKSZ);
|
||||
memset(work, 0, WORKSZ);
|
||||
|
||||
jd.inData = logo_jpg;
|
||||
jd.inPos = 0;
|
||||
jd.outData = decoded;
|
||||
jd.outW = TESTW;
|
||||
jd.outH = TESTH;
|
||||
|
||||
r = jd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
r = jd_decomp(&decoder, outfunc, 0);
|
||||
TEST_ASSERT_EQUAL(r, JDR_OK);
|
||||
|
||||
p = decoded + 2;
|
||||
for (y = 0; y < TESTH; y++) {
|
||||
for (x = 0; x < TESTH; x++) {
|
||||
v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
|
||||
printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
|
||||
p += 3;
|
||||
}
|
||||
printf("%c%c", ' ', '\n');
|
||||
}
|
||||
|
||||
free(work);
|
||||
free(decoded);
|
||||
}
|
205
components/esp32/test/test_unal_dma.c
Normal file
205
components/esp32/test/test_unal_dma.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/lldesc.h"
|
||||
#include "rom/gpio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
|
||||
|
||||
#define DPORT_I2S0_CLK_EN (BIT(4))
|
||||
#define DPORT_I2S0_RST (BIT(4))
|
||||
|
||||
static volatile lldesc_t dmaDesc[2];
|
||||
|
||||
|
||||
//hacked up routine to essentially do a memcpy() using dma. Supports max 4K-1 bytes.
|
||||
static void dmaMemcpy(void *in, void *out, int len)
|
||||
{
|
||||
volatile int i;
|
||||
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
|
||||
|
||||
//Init pins to i2s functions
|
||||
SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
|
||||
|
||||
WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
|
||||
WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
|
||||
// WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
|
||||
|
||||
//GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
|
||||
WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
|
||||
|
||||
//Reset I2S subsystem
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_I2S_SIG_LOOPBACK);
|
||||
WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
|
||||
|
||||
WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
|
||||
(16 << I2S_RX_BITS_MOD_S) |
|
||||
(16 << I2S_TX_BITS_MOD_S) |
|
||||
(1 << I2S_RX_BCK_DIV_NUM_S) |
|
||||
(1 << I2S_TX_BCK_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
|
||||
I2S_CLKA_ENA | I2S_CLK_EN |
|
||||
(1 << I2S_CLKM_DIV_A_S) |
|
||||
(1 << I2S_CLKM_DIV_B_S) |
|
||||
(1 << I2S_CLKM_DIV_NUM_S));
|
||||
WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
|
||||
(32 << I2S_TX_DATA_NUM_S) | //Low watermark for IRQ
|
||||
(32 << I2S_RX_DATA_NUM_S));
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
|
||||
|
||||
WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
|
||||
|
||||
//Invert WS to active-low
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
|
||||
WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
|
||||
|
||||
//--
|
||||
//Fill DMA descriptor
|
||||
dmaDesc[0].length = len;
|
||||
dmaDesc[0].size = len;
|
||||
dmaDesc[0].owner = 1;
|
||||
dmaDesc[0].sosf = 0;
|
||||
dmaDesc[0].buf = (uint8_t *)in;
|
||||
dmaDesc[0].offset = 0; //unused in hw
|
||||
dmaDesc[0].empty = 0;
|
||||
dmaDesc[0].eof = 1;
|
||||
dmaDesc[1].length = len;
|
||||
dmaDesc[1].size = len;
|
||||
dmaDesc[1].owner = 1;
|
||||
dmaDesc[1].sosf = 0;
|
||||
dmaDesc[1].buf = (uint8_t *)out;
|
||||
dmaDesc[1].offset = 0; //unused in hw
|
||||
dmaDesc[1].empty = 0;
|
||||
dmaDesc[1].eof = 1;
|
||||
|
||||
//Reset DMA
|
||||
SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
|
||||
|
||||
//Reset I2S FIFO
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
//Set desc addr
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
|
||||
CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
|
||||
|
||||
WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
|
||||
|
||||
//Enable and configure DMA
|
||||
WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN |
|
||||
I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
|
||||
I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
|
||||
|
||||
//Start transmission
|
||||
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
|
||||
SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
//Clear int flags
|
||||
WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
|
||||
//--
|
||||
//No need to finish if no DMA transfer going on
|
||||
if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Wait till fifo done
|
||||
while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
|
||||
//Wait for last bytes to leave i2s xmit thing
|
||||
//ToDo: poll bit in next hw
|
||||
for (i = 0; i < (1 << 8); i++);
|
||||
while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
|
||||
|
||||
//Reset I2S for next transfer
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
|
||||
CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
|
||||
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
|
||||
|
||||
// for (i=0; i<(1<<8); i++);
|
||||
while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
|
||||
|
||||
}
|
||||
|
||||
|
||||
int mymemcmp(char *a, char *b, int len)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < len; x++) {
|
||||
if (a[x] != b[x]) {
|
||||
printf("Not equal at byte %d. a=%x, b=%x\n", x, (int)a[x], (int)b[x]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE("Unaligned DMA test (needs I2S)", "[hw]")
|
||||
{
|
||||
int x;
|
||||
char src[2049], dest[2049];
|
||||
for (x = 0; x < sizeof(src); x++) {
|
||||
src[x] = x & 0xff;
|
||||
}
|
||||
|
||||
printf("Aligned dma\n");
|
||||
memset(dest, 0, 2049);
|
||||
dmaMemcpy(src, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src, dest, 2048) == 0);
|
||||
printf("Src unaligned\n");
|
||||
dmaMemcpy(src + 1, dest, 2048 + 1);
|
||||
TEST_ASSERT(mymemcmp(src + 1, dest, 2048) == 0);
|
||||
printf("Dst unaligned\n");
|
||||
dmaMemcpy(src, dest + 1, 2048 + 2);
|
||||
TEST_ASSERT(mymemcmp(src, dest + 1, 2048) == 0);
|
||||
}
|
||||
|
|
@ -895,7 +895,8 @@ typedef struct xSTATIC_TCB
|
|||
uint32_t ulDummy18;
|
||||
uint32_t ucDummy19;
|
||||
#endif
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
#if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) \
|
||||
|| ( portUSING_MPU_WRAPPERS == 1 ) )
|
||||
uint8_t uxDummy20;
|
||||
#endif
|
||||
|
||||
|
@ -927,7 +928,6 @@ typedef struct xSTATIC_QUEUE
|
|||
|
||||
StaticList_t xDummy3[ 2 ];
|
||||
UBaseType_t uxDummy4[ 3 ];
|
||||
BaseType_t ucDummy5[ 2 ];
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucDummy6;
|
||||
|
@ -943,12 +943,12 @@ typedef struct xSTATIC_QUEUE
|
|||
#endif
|
||||
|
||||
struct {
|
||||
volatile uint32_t mux;
|
||||
volatile uint32_t ucDummy10;
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
const char *lastLockedFn;
|
||||
int lastLockedLine;
|
||||
void *pvDummy8;
|
||||
UBaseType_t uxDummy11;
|
||||
#endif
|
||||
} mux;
|
||||
} sDummy12;
|
||||
|
||||
} StaticQueue_t;
|
||||
typedef StaticQueue_t StaticSemaphore_t;
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
|
||||
/* configASSERT behaviour */
|
||||
#ifndef __ASSEMBLER__
|
||||
#include <stdlib.h> /* for abort() */
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#if defined(CONFIG_FREERTOS_ASSERT_DISABLE)
|
||||
|
@ -126,8 +127,6 @@
|
|||
#endif
|
||||
|
||||
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
#define UNTESTED_FUNCTION() { ets_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
|
||||
#else
|
||||
#define UNTESTED_FUNCTION()
|
||||
|
|
|
@ -190,6 +190,10 @@ struct xLIST_ITEM
|
|||
};
|
||||
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticListItem_t) == sizeof(ListItem_t), "StaticListItem_t != ListItem_t");
|
||||
#endif
|
||||
|
||||
struct xMINI_LIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
|
@ -199,6 +203,11 @@ struct xMINI_LIST_ITEM
|
|||
};
|
||||
typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticMiniListItem_t) == sizeof(MiniListItem_t), "StaticMiniListItem_t != MiniListItem_t");
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Definition of the type of queue used by the scheduler.
|
||||
*/
|
||||
|
@ -211,6 +220,10 @@ typedef struct xLIST
|
|||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
} List_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticList_t) == sizeof(List_t), "StaticList_t != List_t");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Access macro to set the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
|
|
|
@ -179,6 +179,11 @@ typedef struct QueueDefinition
|
|||
name below to enable the use of older kernel aware debuggers. */
|
||||
typedef xQUEUE Queue_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticQueue_t) == sizeof(Queue_t), "StaticQueue_t != Queue_t");
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -609,9 +609,9 @@ void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size,
|
|||
void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
portENTER_CRITICAL_ISR(&rb->mux);
|
||||
portENTER_CRITICAL(&rb->mux);
|
||||
rb->returnItemToRingbufImpl(rb, item);
|
||||
portEXIT_CRITICAL_ISR(&rb->mux);
|
||||
portEXIT_CRITICAL(&rb->mux);
|
||||
xSemaphoreGive(rb->free_space_sem);
|
||||
}
|
||||
|
||||
|
|
|
@ -242,6 +242,10 @@ typedef struct tskTaskControlBlock
|
|||
below to enable the use of older kernel aware debuggers. */
|
||||
typedef tskTCB TCB_t;
|
||||
|
||||
#if __GNUC_PREREQ(4, 6)
|
||||
_Static_assert(sizeof(StaticTask_t) == sizeof(TCB_t), "StaticTask_t != TCB_t");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some kernel aware debuggers require the data the debugger needs access to to
|
||||
* be global, rather than file scope.
|
||||
|
|
5
components/freertos/test/component.mk
Normal file
5
components/freertos/test/component.mk
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
229
components/freertos/test/test_freertos.c
Normal file
229
components/freertos/test/test_freertos.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
void ets_isr_unmask(uint32_t unmask);
|
||||
|
||||
static xQueueHandle myQueue;
|
||||
static xQueueHandle uartRxQueue;
|
||||
|
||||
int ctr;
|
||||
|
||||
#if 1
|
||||
//Idle-loop for delay. Tests involuntary yielding
|
||||
static void cvTaskDelay(int dummy)
|
||||
{
|
||||
volatile int i;
|
||||
for (i = 0; i < (1 << 17); i++);
|
||||
}
|
||||
#else
|
||||
//Delay task execution using FreeRTOS methods. Tests voluntary yielding.
|
||||
#define cvTaskDelay(x) vTaskDelay(x)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void dosegfault3(int i)
|
||||
{
|
||||
volatile char *p = (volatile char *)0;
|
||||
*p = i;
|
||||
}
|
||||
|
||||
static void dosegfault2(int i)
|
||||
{
|
||||
if (i > 3) {
|
||||
dosegfault3(i);
|
||||
}
|
||||
}
|
||||
|
||||
static void dosegfault(int i)
|
||||
{
|
||||
if (i < 5) {
|
||||
dosegfault(i + 1);
|
||||
}
|
||||
dosegfault2(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void queueSender(void *pvParameters)
|
||||
{
|
||||
int myCtr = xPortGetCoreID() * 100000;
|
||||
while (1) {
|
||||
printf("Core %d: Send to queue: %d\n", xPortGetCoreID(), myCtr);
|
||||
xQueueSend(myQueue, (void *)(&myCtr), portMAX_DELAY);
|
||||
printf("Send to queue done.\n");
|
||||
cvTaskDelay(100);
|
||||
myCtr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void queueReceiver(void *pvParameters)
|
||||
{
|
||||
int theCtr;
|
||||
while (1) {
|
||||
xQueueReceive(myQueue, &theCtr, portMAX_DELAY);
|
||||
printf("Core %d: Receive from queue: %d\n", xPortGetCoreID(), theCtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void tskone(void *pvParameters)
|
||||
{
|
||||
// char *p=(char *)0;
|
||||
while (1) {
|
||||
ctr++;
|
||||
// if (ctr>60) dosegfault(3);
|
||||
printf("Task1, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
|
||||
cvTaskDelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static void tsktwo(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
ctr++;
|
||||
printf("Task2, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
|
||||
cvTaskDelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskthree(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
ctr++;
|
||||
printf("Task3, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
|
||||
cvTaskDelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskfour(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
ctr++;
|
||||
printf("Task4, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
|
||||
cvTaskDelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskfive(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
ctr++;
|
||||
printf("Task5, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
|
||||
cvTaskDelay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskyield(void *pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
portYIELD();
|
||||
}
|
||||
}
|
||||
|
||||
static void tskUartRecv(void *pvParameters)
|
||||
{
|
||||
char c;
|
||||
while (1) {
|
||||
xQueueReceive(uartRxQueue, &c, portMAX_DELAY);
|
||||
printf("Uart received %c!\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uartIsrHdl(void *arg)
|
||||
{
|
||||
char c;
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
SET_PERI_REG_MASK(UART_INT_CLR_REG(0), UART_RXFIFO_FULL_INT_CLR);
|
||||
while (READ_PERI_REG(UART_STATUS_REG(0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
||||
c = READ_PERI_REG(UART_FIFO_REG(0));
|
||||
xQueueSendFromISR(uartRxQueue, &c, &xHigherPriorityTaskWoken);
|
||||
printf("ISR: %c\n", c);
|
||||
}
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void uartRxInit(xQueueHandle q)
|
||||
{
|
||||
uint32_t reg_val;
|
||||
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
|
||||
|
||||
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
|
||||
|
||||
// reg_val = READ_PERI_REG(UART_CONF1(0));
|
||||
reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
|
||||
WRITE_PERI_REG(UART_CONF1_REG(0), reg_val);
|
||||
CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_TXFIFO_EMPTY_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RXFIFO_FULL_INT_ENA);
|
||||
|
||||
printf("Enabling int %d\n", ETS_UART0_INUM);
|
||||
REG_SET_FIELD(DPORT_PRO_UART_INTR_MAP_REG, DPORT_PRO_UART_INTR_MAP, ETS_UART0_INUM);
|
||||
REG_SET_FIELD(DPORT_PRO_UART1_INTR_MAP_REG, DPORT_PRO_UART1_INTR_MAP, ETS_UART0_INUM);
|
||||
|
||||
xt_set_interrupt_handler(ETS_UART0_INUM, uartIsrHdl, NULL);
|
||||
xt_ints_on(1 << ETS_UART0_INUM);
|
||||
|
||||
}
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Bunch of FreeRTOS tests", "[freertos]")
|
||||
{
|
||||
char *tst;
|
||||
TaskHandle_t th[12];
|
||||
int i;
|
||||
printf("%s\n", __FUNCTION__);
|
||||
tst = pvPortMalloc(16);
|
||||
printf("Test malloc returns addr %p\n", tst);
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
myQueue = xQueueCreate(10, sizeof(int));
|
||||
uartRxQueue = xQueueCreate(256, sizeof(char));
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
|
||||
printf("Creating tasks\n");
|
||||
xTaskCreatePinnedToCore(tskyield , "tskyield1" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(tskyield , "tskyield2" , 2048, NULL, 3, &th[1], 1);
|
||||
|
||||
xTaskCreatePinnedToCore(tskone , "tskone" , 2048, NULL, 3, &th[2], 0);
|
||||
xTaskCreatePinnedToCore(tsktwo , "tsktwo" , 2048, NULL, 3, &th[3], 1);
|
||||
xTaskCreatePinnedToCore(tskthree, "tskthree", 2048, NULL, 3, &th[4], 0);
|
||||
xTaskCreatePinnedToCore(tskfour , "tskfour" , 2048, NULL, 3, &th[5], tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(tskfive , "tskfive" , 2048, NULL, 3, &th[6], tskNO_AFFINITY);
|
||||
xTaskCreatePinnedToCore(queueSender , "qsend1" , 2048, NULL, 3, &th[7], 0);
|
||||
xTaskCreatePinnedToCore(queueSender , "qsend2" , 2048, NULL, 3, &th[8], 1);
|
||||
xTaskCreatePinnedToCore(queueReceiver , "qrecv1" , 2048, NULL, 3, &th[9], 1);
|
||||
xTaskCreatePinnedToCore(queueReceiver , "qrecv2" , 2048, NULL, 3, &th[10], 0);
|
||||
xTaskCreatePinnedToCore(tskUartRecv , "tskuart" , 2048, NULL, 4, &th[11], 1);
|
||||
printf("Free heap: %u\n", xPortGetFreeHeapSize());
|
||||
uartRxInit(uartRxQueue);
|
||||
|
||||
// Let stuff run for 20s
|
||||
vTaskDelay(20000 / portTICK_PERIOD_MS);
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 12; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
xt_ints_off(1 << ETS_UART0_INUM);
|
||||
}
|
||||
|
105
components/freertos/test/test_freertos_eventgroups.c
Normal file
105
components/freertos/test/test_freertos_eventgroups.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
|
||||
#define BIT_CALL (1 << 0)
|
||||
#define BIT_RESPONSE(TASK) (1 << (TASK+1))
|
||||
#define ALL_RESPONSE_BITS (((1 << NUM_TASKS) - 1) << 1)
|
||||
|
||||
static const int NUM_TASKS = 4;
|
||||
static const int COUNT = 4000;
|
||||
static EventGroupHandle_t eg;
|
||||
|
||||
static void task_event_group_call_response(void *param)
|
||||
{
|
||||
int task_num = (int)param;
|
||||
|
||||
printf("Started %d\n", task_num);
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
/* Wait until the common "call" bit is set, starts off all tasks
|
||||
(clear on return) */
|
||||
while (!xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY)) {
|
||||
}
|
||||
|
||||
/* Set our individual "response" bit */
|
||||
xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
|
||||
}
|
||||
|
||||
printf("Task %d done\n", task_num);
|
||||
|
||||
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeRTOS Event Groups", "[freertos]")
|
||||
{
|
||||
eg = xEventGroupCreate();
|
||||
|
||||
/* Note: task_event_group_call_response all have higher priority than us, so will block together.
|
||||
|
||||
This is important because we need to know they'll all have blocked on BIT_CALL each time we
|
||||
signal it, or they get out of sync.
|
||||
*/
|
||||
for (int c = 0; c < NUM_TASKS; c++) {
|
||||
xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
|
||||
}
|
||||
/* Scheduler weirdness, if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */
|
||||
vTaskDelay(10);
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
if (i % 100 == 0) {
|
||||
//printf("Call %d\n", i);
|
||||
}
|
||||
/* signal all tasks with "CALL" bit... */
|
||||
xEventGroupSetBits(eg, BIT_CALL);
|
||||
|
||||
while (xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, portMAX_DELAY) != ALL_RESPONSE_BITS) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define BIT_DONE(X) (1<<(NUM_TASKS+1+X))
|
||||
|
||||
static void task_test_sync(void *param)
|
||||
{
|
||||
int task_num = (int)param;
|
||||
|
||||
printf("Started %d\n", task_num);
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
/* set our bit, and wait on all tasks to set their bits */
|
||||
xEventGroupSync(eg, BIT_RESPONSE(task_num), ALL_RESPONSE_BITS, portMAX_DELAY);
|
||||
/* clear our bit */
|
||||
xEventGroupClearBits(eg, BIT_RESPONSE(task_num));
|
||||
}
|
||||
int after_done = xEventGroupSetBits(eg, BIT_DONE(task_num));
|
||||
|
||||
printf("Done %d = %x\n", task_num, after_done);
|
||||
|
||||
/* Delay is due to not-yet-fixed bug with deleting tasks at same time */
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeRTOS Event Group Sync", "[freertos]")
|
||||
{
|
||||
eg = xEventGroupCreate();
|
||||
|
||||
for (int c = 0; c < NUM_TASKS; c++) {
|
||||
xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
|
||||
}
|
||||
|
||||
for (int c = 0; c < NUM_TASKS; c++) {
|
||||
printf("Waiting on %d (%x)\n", c, BIT_DONE(c));
|
||||
xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
22
components/freertos/test/test_freertos_task_delete.c
Normal file
22
components/freertos/test/test_freertos_task_delete.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
|
||||
static void task_delete_self(void *param)
|
||||
{
|
||||
printf("Task %p running on core %d. Deleting shortly...\n", xTaskGetCurrentTaskHandle(), xPortGetCoreID());
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
|
||||
{
|
||||
xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
|
||||
xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
printf("Done?\n");
|
||||
}
|
60
components/freertos/test/test_newlib_reent.c
Normal file
60
components/freertos/test/test_newlib_reent.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
volatile static int done;
|
||||
volatile static int error;
|
||||
|
||||
static void tskTestRand(void *pvParameters)
|
||||
{
|
||||
int l;
|
||||
srand(0x1234);
|
||||
vTaskDelay((int)pvParameters / portTICK_PERIOD_MS);
|
||||
l = rand();
|
||||
printf("Rand1: %d\n", l);
|
||||
if (l != 869320854) {
|
||||
error++;
|
||||
}
|
||||
vTaskDelay((int)pvParameters / portTICK_PERIOD_MS);
|
||||
l = rand();
|
||||
printf("Rand2: %d\n", l);
|
||||
if (l != 1148737841) {
|
||||
error++;
|
||||
}
|
||||
done++;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Test for per-task non-reentrant tasks", "[freertos]")
|
||||
{
|
||||
done = 0;
|
||||
error = 0;
|
||||
xTaskCreatePinnedToCore(tskTestRand, "tsk1", 2048, (void *)100, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestRand, "tsk2", 2048, (void *)200, 3, NULL, 0);
|
||||
xTaskCreatePinnedToCore(tskTestRand, "tsk3", 2048, (void *)300, 3, NULL, 1);
|
||||
xTaskCreatePinnedToCore(tskTestRand, "tsk4", 2048, (void *)400, 3, NULL, 0);
|
||||
while (done != 4) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
TEST_ASSERT(error == 0);
|
||||
}
|
||||
|
26
components/freertos/test/test_panic.c
Normal file
26
components/freertos/test/test_panic.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
TEST_CASE("Panic handler", "[freertos]")
|
||||
{
|
||||
volatile int *i;
|
||||
i = (volatile int *)0x0;
|
||||
*i = 1;
|
||||
}
|
||||
|
197
components/freertos/test/test_ringbuf.c
Normal file
197
components/freertos/test/test_ringbuf.c
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
Test for multicore FreeRTOS ringbuffer.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void ets_isr_unmask(uint32_t unmask);
|
||||
|
||||
static RingbufHandle_t rb;
|
||||
typedef enum {
|
||||
TST_MOSTLYFILLED,
|
||||
TST_MOSTLYEMPTY,
|
||||
TST_INTTOTASK,
|
||||
TST_TASKTOINT,
|
||||
} testtype_t;
|
||||
|
||||
static volatile testtype_t testtype;
|
||||
|
||||
static void task1(void *arg)
|
||||
{
|
||||
testtype_t oldtest;
|
||||
char buf[100];
|
||||
int i = 0;
|
||||
int x, r;
|
||||
while (1) {
|
||||
oldtest = testtype;
|
||||
if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
|
||||
for (x = 0; x < 10; x++) {
|
||||
sprintf(buf, "This is test %d item %d.", (int)testtype, i++);
|
||||
ets_printf("TSK w");
|
||||
xRingbufferPrintInfo(rb);
|
||||
r = xRingbufferSend(rb, buf, strlen(buf) + 1, 2000 / portTICK_PERIOD_MS);
|
||||
if (!r) {
|
||||
printf("Test %d: Timeout on send!\n", (int)testtype);
|
||||
}
|
||||
if (testtype == TST_MOSTLYEMPTY) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
//Send NULL event to stop other side.
|
||||
r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
while (oldtest == testtype) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void task2(void *arg)
|
||||
{
|
||||
testtype_t oldtest;
|
||||
char *buf;
|
||||
size_t len;
|
||||
while (1) {
|
||||
oldtest = testtype;
|
||||
if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
|
||||
while (1) {
|
||||
ets_printf("TSK r");
|
||||
xRingbufferPrintInfo(rb);
|
||||
buf = xRingbufferReceive(rb, &len, 2000 / portTICK_PERIOD_MS);
|
||||
if (buf == NULL) {
|
||||
printf("Test %d: Timeout on recv!\n", (int)testtype);
|
||||
} else if (len == 0) {
|
||||
printf("End packet received.\n");
|
||||
vRingbufferReturnItem(rb, buf);
|
||||
break;
|
||||
} else {
|
||||
printf("Received: %s (%d bytes, %p)\n", buf, len, buf);
|
||||
vRingbufferReturnItem(rb, buf);
|
||||
}
|
||||
if (testtype == TST_MOSTLYFILLED) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (oldtest == testtype) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void uartIsrHdl(void *arg)
|
||||
{
|
||||
char c;
|
||||
char buf[50];
|
||||
char *item;
|
||||
int r;
|
||||
size_t len;
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
SET_PERI_REG_MASK(UART_INT_CLR_REG(0), UART_RXFIFO_FULL_INT_CLR);
|
||||
while (READ_PERI_REG(UART_STATUS_REG(0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
|
||||
c = READ_PERI_REG(UART_FIFO_REG(0));
|
||||
if (c == 'r') {
|
||||
ets_printf("ISR r");
|
||||
xRingbufferPrintInfo(rb);
|
||||
item = xRingbufferReceiveFromISR(rb, &len);
|
||||
if (item == NULL) {
|
||||
ets_printf("ISR recv fail!\n");
|
||||
} else if (len == 0) {
|
||||
ets_printf("ISR recv NULL!\n");
|
||||
vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
|
||||
} else {
|
||||
ets_printf("ISR recv '%s' (%d bytes, %p)\n", buf, len, buf);
|
||||
vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
} else {
|
||||
sprintf(buf, "UART: %c", c);
|
||||
ets_printf("ISR w");
|
||||
xRingbufferPrintInfo(rb);
|
||||
r = xRingbufferSendFromISR(rb, buf, strlen(buf) + 1, &xHigherPriorityTaskWoken);
|
||||
if (!r) {
|
||||
ets_printf("ISR send fail\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void uartRxInit()
|
||||
{
|
||||
uint32_t reg_val;
|
||||
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
|
||||
|
||||
// reg_val = READ_PERI_REG(UART_CONF1(0));
|
||||
reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
|
||||
WRITE_PERI_REG(UART_CONF1_REG(0), reg_val);
|
||||
CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_TXFIFO_EMPTY_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
|
||||
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RXFIFO_FULL_INT_ENA);
|
||||
|
||||
printf("Enabling int %d\n", ETS_UART0_INUM);
|
||||
REG_SET_FIELD(DPORT_PRO_UART_INTR_MAP_REG, DPORT_PRO_UART_INTR_MAP, ETS_UART0_INUM);
|
||||
REG_SET_FIELD(DPORT_PRO_UART1_INTR_MAP_REG, DPORT_PRO_UART1_INTR_MAP, ETS_UART0_INUM);
|
||||
|
||||
xt_set_interrupt_handler(ETS_UART0_INUM, uartIsrHdl, NULL);
|
||||
xt_ints_on(1 << ETS_UART0_INUM);
|
||||
|
||||
}
|
||||
|
||||
static void testRingbuffer(int type)
|
||||
{
|
||||
TaskHandle_t th[2];
|
||||
int i;
|
||||
rb = xRingbufferCreate(32 * 3, type);
|
||||
|
||||
testtype = TST_MOSTLYFILLED;
|
||||
|
||||
xTaskCreatePinnedToCore(task1 , "tskone" , 2048, NULL, 3, &th[0], 0);
|
||||
xTaskCreatePinnedToCore(task2 , "tsktwo" , 2048, NULL, 3, &th[1], 0);
|
||||
uartRxInit();
|
||||
|
||||
printf("Press 'r' to read an event in isr, any other key to write one.\n");
|
||||
printf("Test: mostlyfilled; putting 10 items in ringbuff ASAP, reading 1 a second\n");
|
||||
vTaskDelay(15000 / portTICK_PERIOD_MS);
|
||||
printf("Test: mostlyempty; putting 10 items in ringbuff @ 1/sec, reading as fast as possible\n");
|
||||
testtype = TST_MOSTLYEMPTY;
|
||||
vTaskDelay(15000 / portTICK_PERIOD_MS);
|
||||
|
||||
//Shut down all the tasks
|
||||
for (i = 0; i < 2; i++) {
|
||||
vTaskDelete(th[i]);
|
||||
}
|
||||
xt_ints_off(1 << ETS_UART0_INUM);
|
||||
}
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]")
|
||||
{
|
||||
testRingbuffer(0);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]")
|
||||
{
|
||||
testRingbuffer(1);
|
||||
}
|
||||
|
58
components/freertos/test/test_tls_deletecb.c
Normal file
58
components/freertos/test/test_tls_deletecb.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
|
||||
|
||||
|
||||
static void tskdelcb(int no, void *arg)
|
||||
{
|
||||
printf("Delete callback: %d = %p!\n", no, arg);
|
||||
}
|
||||
|
||||
|
||||
static void tska(void *pvParameters)
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xAAAAAAAA, tskdelcb);
|
||||
while (1) {
|
||||
vTaskDelay(10000000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static void tskb(void *pvParameters)
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xBBBBBBBB, tskdelcb);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TaskHandle_t a = (TaskHandle_t)pvParameters;
|
||||
printf("Killing task A\n");
|
||||
vTaskDelete(a);
|
||||
while (1) {
|
||||
vTaskDelay(10000000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: split this thing into separate orthogonal tests
|
||||
TEST_CASE("Freertos TLS delete cb", "[freertos]")
|
||||
{
|
||||
TaskHandle_t a, b;
|
||||
|
||||
xTaskCreatePinnedToCore(tska , "tska" , 2048, NULL, 3, &a, 0);
|
||||
xTaskCreatePinnedToCore(tskb , "tska" , 2048, a, 3, &b, 0);
|
||||
|
||||
// Let stuff run for 20s
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
printf("Killing task B\n");
|
||||
//Shut down b
|
||||
vTaskDelete(b);
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@ Config: {execute count: 1, execute order: in order}
|
|||
DUT: [UT1]
|
||||
Filter:
|
||||
- Add:
|
||||
ID: [SYS_OS_0102, SYS_MISC_0103, SYS_MISC_0102, SYS_MISC_0105, SYS_MISC_0104,
|
||||
SYS_MISC_0107, SYS_MISC_0106, SYS_MISC_0109, SYS_MISC_0108, SYS_MISC_0112, SYS_MISC_0113,
|
||||
SYS_MISC_0110, SYS_MISC_0111, SYS_MISC_0115, SYS_LIB_0103, SYS_LIB_0102, SYS_LIB_0101,
|
||||
SYS_LIB_0106, SYS_LIB_0105, SYS_LIB_0104]
|
||||
ID: [SYS_OS_0102, SYS_MISC_0102, SYS_MISC_0107, SYS_MISC_0106, SYS_MISC_0109,
|
||||
SYS_MISC_0108, SYS_MISC_0112, SYS_MISC_0113, SYS_MISC_0110, SYS_MISC_0111, SYS_LIB_0103,
|
||||
SYS_LIB_0102, SYS_LIB_0101, SYS_LIB_0106, SYS_LIB_0105, SYS_LIB_0104]
|
||||
|
|
|
@ -18,10 +18,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#include <rom/ets_sys.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "lwip/tcp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/priv/memp_priv.h"
|
||||
#include "lwip/memp.h"
|
||||
|
||||
#define DBG_LWIP_IP_SHOW(info, ip) printf("%s type=%d ip=%x\n", (info), (ip).type, (ip).u_addr.ip4.addr)
|
||||
#define DBG_LWIP_IP_PCB_SHOW(pcb) \
|
||||
|
@ -127,3 +129,22 @@ void dbg_lwip_udp_rxtx_show(void)
|
|||
printf("TBC\n");
|
||||
}
|
||||
|
||||
#if (ESP_CNT_DEBUG == 1)
|
||||
|
||||
uint32_t g_lwip_mem_cnt[MEMP_MAX][2];
|
||||
extern const struct memp_desc * const memp_pools[MEMP_MAX];
|
||||
|
||||
void dbg_lwip_cnt_show(void)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
printf("-----lwip memory counter-----\n");
|
||||
printf("%6s %8s %8s\n", "index", "alloc", "free");
|
||||
for (i=0; i<MEMP_MAX; i++){
|
||||
printf("%6u %8u %8u\n", i, g_lwip_mem_cnt[i][0], g_lwip_mem_cnt[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2776,7 +2776,11 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
|||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
/* @todo: this does not work for datagram sockets, yet */
|
||||
#if CONFIG_MDNS
|
||||
//LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
|
||||
#else
|
||||
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
|
||||
#endif
|
||||
if (*(const int*)optval) {
|
||||
netconn_set_ipv6only(sock->conn, 1);
|
||||
} else {
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "lwip/netif.h"
|
||||
#include "lwip/autoip.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/dhcp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -269,6 +270,12 @@ autoip_bind(struct netif *netif)
|
|||
netif_set_addr(netif, &autoip->llipaddr, &sn_mask, &gw_addr);
|
||||
/* interface is used by routing now that an address is set */
|
||||
|
||||
#if ESP_LWIP
|
||||
struct dhcp *dhcp = netif->dhcp;
|
||||
if (dhcp->cb != NULL) {
|
||||
dhcp->cb();
|
||||
}
|
||||
#endif
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -632,6 +632,22 @@ nd6_input(struct pbuf *p, struct netif *inp)
|
|||
pbuf_free(p);
|
||||
}
|
||||
|
||||
#ifdef ESP_LWIP
|
||||
|
||||
/** Set callback for ipv6 addr status changed .
|
||||
*
|
||||
* @param netif the netif from which to remove the struct dhcp
|
||||
* @param cb callback for dhcp
|
||||
*/
|
||||
void nd6_set_cb(struct netif *netif, void (*cb)(struct netif *netif, u8_t ip_index))
|
||||
{
|
||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||
|
||||
if (netif != NULL && netif_is_up(netif)) {
|
||||
netif->ipv6_addr_cb = cb;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Periodic timer for Neighbor discovery functions:
|
||||
|
@ -797,6 +813,12 @@ nd6_tmr(void)
|
|||
if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) {
|
||||
/* No NA received in response. Mark address as valid. */
|
||||
netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED;
|
||||
#ifdef ESP_LWIP
|
||||
if (netif->ipv6_addr_cb != NULL) {
|
||||
netif->ipv6_addr_cb(netif, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO implement preferred and valid lifetimes. */
|
||||
} else if (netif->flags & NETIF_FLAG_UP) {
|
||||
#if LWIP_IPV6_MLD
|
||||
|
|
|
@ -968,9 +968,6 @@ netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit)
|
|||
}
|
||||
}
|
||||
|
||||
#if ESP_LWIP
|
||||
ip6_addr_set( ip_2_ip6(&netif->link_local_addr), ip_2_ip6(&netif->ip6_addr[0]) );
|
||||
#endif
|
||||
|
||||
/* Set address state. */
|
||||
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
||||
|
@ -1022,44 +1019,6 @@ netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chos
|
|||
return ERR_VAL;
|
||||
}
|
||||
|
||||
|
||||
#if ESP_LWIP
|
||||
void
|
||||
netif_create_ip4_linklocal_address(struct netif * netif)
|
||||
{
|
||||
#if 1
|
||||
ip_addr_t linklocal;
|
||||
ip_addr_t linklocal_mask;
|
||||
ip4_addr_t addr = {0};
|
||||
/* Link-local prefix and mask. */
|
||||
IP4_ADDR(ip_2_ip4(&linklocal), 169, 254, 0, 0);
|
||||
IP4_ADDR(ip_2_ip4(&linklocal_mask), 255, 255, 0, 0);
|
||||
|
||||
if (!ip4_addr_netcmp( ip_2_ip4(&linklocal), ip_2_ip4(&netif->link_local_addr), ip_2_ip4(&linklocal_mask) ) &&
|
||||
!ip4_addr_isany(ip_2_ip4(&netif->ip_addr)) ) {
|
||||
IP4_ADDR( ip_2_ip4(&netif->link_local_addr), 169, 254, ip4_addr3( ip_2_ip4(&netif->ip_addr) )
|
||||
, ip4_addr4( ip_2_ip4(&netif->ip_addr) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
while ( !(addr.addr) || !ip4_addr4(&addr) )
|
||||
//os_get_random((unsigned char *)&addr, sizeof(addr));
|
||||
addr.addr = LWIP_RAND();
|
||||
|
||||
|
||||
if ( ip_2_ip4(&netif->netmask)->addr > IP_CLASSB_NET &&
|
||||
!ip4_addr_isany( ip_2_ip4(&netif->ip_addr) )) { // random host address
|
||||
IP4_ADDR( ip_2_ip4(&netif->link_local_addr), 169, 254, ip4_addr3( ip_2_ip4(&netif->ip_addr))
|
||||
, ip4_addr4(&addr));
|
||||
} else {
|
||||
IP4_ADDR( ip_2_ip4(&netif->link_local_addr), 169, 254, ip4_addr3(&addr), ip4_addr4(&addr) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Dummy IPv6 output function for netifs not supporting IPv6
|
||||
*/
|
||||
static err_t
|
||||
|
|
|
@ -1389,59 +1389,58 @@ tcp_kill_timewait(void)
|
|||
}
|
||||
|
||||
#if ESP_LWIP
|
||||
/**
|
||||
* Kills the oldest connection that is in FIN_WAIT_2 state.
|
||||
* Called from tcp_alloc() if no more connections are available.
|
||||
*/
|
||||
static void tcp_kill_finwait2(void)
|
||||
{
|
||||
struct tcp_pcb *pcb, *inactive;
|
||||
u32_t inactivity;
|
||||
/* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */
|
||||
inactivity = 0;
|
||||
inactive = NULL;
|
||||
for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->state == FIN_WAIT_2) {
|
||||
if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {
|
||||
inactivity = tcp_ticks - pcb->tmr;
|
||||
inactive = pcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inactive != NULL) {
|
||||
tcp_pcb_remove(&tcp_active_pcbs, inactive);
|
||||
memp_free(MEMP_TCP_PCB, inactive);
|
||||
}
|
||||
}
|
||||
typedef struct {
|
||||
u8_t time_wait;
|
||||
u8_t closing;
|
||||
u8_t fin_wait2;
|
||||
u8_t last_ack;
|
||||
u8_t fin_wait1;
|
||||
u8_t listen;
|
||||
u8_t bound;
|
||||
u8_t total;
|
||||
}tcp_pcb_num_t;
|
||||
|
||||
/**
|
||||
* Kills the oldest connection that is in LAST_ACK state.
|
||||
* Called from tcp_alloc() if no more connections are available.
|
||||
*/
|
||||
static void tcp_kill_lastack(void)
|
||||
void tcp_pcb_num_cal(tcp_pcb_num_t *tcp_pcb_num)
|
||||
{
|
||||
struct tcp_pcb *pcb, *inactive;
|
||||
u32_t inactivity;
|
||||
/* Go through the list of LAST_ACK pcbs and get the oldest pcb. */
|
||||
inactivity = 0;
|
||||
inactive = NULL;
|
||||
for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
if (pcb->state == LAST_ACK) {
|
||||
if ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {
|
||||
inactivity = tcp_ticks - pcb->tmr;
|
||||
inactive = pcb;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (inactive != NULL) {
|
||||
tcp_pcb_remove(&tcp_active_pcbs, inactive);
|
||||
memp_free(MEMP_TCP_PCB, inactive);
|
||||
}
|
||||
struct tcp_pcb_listen *listen;
|
||||
struct tcp_pcb *pcb;
|
||||
|
||||
if (!tcp_pcb_num){
|
||||
return;
|
||||
}
|
||||
|
||||
memset(tcp_pcb_num, 0, sizeof(*tcp_pcb_num));
|
||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
tcp_pcb_num->total ++;
|
||||
tcp_pcb_num->time_wait ++;
|
||||
}
|
||||
|
||||
for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
|
||||
tcp_pcb_num->total ++;
|
||||
if (pcb->state == FIN_WAIT_2){
|
||||
tcp_pcb_num->fin_wait2 ++;
|
||||
} else if (pcb->state == LAST_ACK) {
|
||||
tcp_pcb_num->last_ack ++;
|
||||
} else if (pcb->state == CLOSING) {
|
||||
tcp_pcb_num->closing ++;
|
||||
} else if (pcb->state == FIN_WAIT_1){
|
||||
tcp_pcb_num->fin_wait1 ++;
|
||||
}
|
||||
}
|
||||
|
||||
for (listen = tcp_listen_pcbs.listen_pcbs; listen != NULL; listen = listen->next){
|
||||
tcp_pcb_num->total ++;
|
||||
tcp_pcb_num->listen ++;
|
||||
}
|
||||
|
||||
for (pcb = tcp_bound_pcbs; pcb != NULL; pcb = pcb->next){
|
||||
tcp_pcb_num->total ++;
|
||||
tcp_pcb_num->bound ++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new tcp_pcb structure.
|
||||
*
|
||||
|
@ -1455,34 +1454,34 @@ tcp_alloc(u8_t prio)
|
|||
u32_t iss;
|
||||
|
||||
#if ESP_LWIP
|
||||
/*Kills the oldest connection that is in TIME_WAIT state.*/
|
||||
u8_t time_wait_num = 0;
|
||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
time_wait_num ++;
|
||||
tcp_pcb_num_t tcp_pcb_num;
|
||||
|
||||
tcp_pcb_num_cal(&tcp_pcb_num);
|
||||
|
||||
if (tcp_pcb_num.total >= MEMP_NUM_TCP_PCB){
|
||||
if (tcp_pcb_num.time_wait > 0){
|
||||
tcp_kill_timewait();
|
||||
} else if (tcp_pcb_num.last_ack > 0){
|
||||
tcp_kill_state(LAST_ACK);
|
||||
} else if (tcp_pcb_num.closing > 0){
|
||||
tcp_kill_state(CLOSING);
|
||||
} else if (tcp_pcb_num.fin_wait2 > 0){
|
||||
tcp_kill_state(FIN_WAIT_2);
|
||||
} else if (tcp_pcb_num.fin_wait1 > 0){
|
||||
tcp_kill_state(FIN_WAIT_1);
|
||||
} else {
|
||||
tcp_kill_prio(prio);
|
||||
}
|
||||
}
|
||||
|
||||
if (time_wait_num >= MEMP_NUM_TCP_PCB)
|
||||
tcp_kill_timewait();
|
||||
|
||||
/*Kills the oldest connection that is in FIN_WAIT_2 state.*/
|
||||
time_wait_num = 0;
|
||||
for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
|
||||
if (pcb->state == FIN_WAIT_2)
|
||||
time_wait_num ++;
|
||||
tcp_pcb_num_cal(&tcp_pcb_num);
|
||||
if (tcp_pcb_num.total >= MEMP_NUM_TCP_PCB){
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: no available tcp pcb %d %d %d %d %d %d %d %d\n",
|
||||
tcp_pcb_num.total, tcp_pcb_num.time_wait, tcp_pcb_num.last_ack, tcp_pcb_num.closing,
|
||||
tcp_pcb_num.fin_wait2, tcp_pcb_num.fin_wait1, tcp_pcb_num.listen, tcp_pcb_num.bound));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (time_wait_num >= MEMP_NUM_TCP_PCB)
|
||||
tcp_kill_finwait2();
|
||||
|
||||
/*Kills the oldest connection that is in LAST_ACK state.*/
|
||||
time_wait_num = 0;
|
||||
for (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){
|
||||
if (pcb->state == LAST_ACK)
|
||||
time_wait_num ++;
|
||||
}
|
||||
|
||||
if (time_wait_num >= MEMP_NUM_TCP_PCB)
|
||||
tcp_kill_lastack();
|
||||
#endif
|
||||
|
||||
pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);
|
||||
|
|
|
@ -176,7 +176,8 @@ tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno,
|
|||
struct tcp_seg *seg;
|
||||
u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
|
||||
|
||||
if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {
|
||||
seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
|
||||
if (seg == NULL) {
|
||||
LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_create_segment: no memory.\n"));
|
||||
pbuf_free(p);
|
||||
return NULL;
|
||||
|
|
|
@ -68,8 +68,13 @@ extern "C" {
|
|||
#define ANNOUNCE_NUM 2 /* (number of announcement packets) */
|
||||
#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */
|
||||
#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */
|
||||
#if CONFIG_MDNS
|
||||
#define MAX_CONFLICTS 9 /* (max conflicts before rate limiting) */
|
||||
#define RATE_LIMIT_INTERVAL 20 /* seconds (delay between successive attempts) */
|
||||
#else
|
||||
#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */
|
||||
#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */
|
||||
#endif
|
||||
#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */
|
||||
|
||||
/* AutoIP client states */
|
||||
|
|
|
@ -20,5 +20,6 @@ void dbg_lwip_tcp_pcb_show(void);
|
|||
void dbg_lwip_udp_pcb_show(void);
|
||||
void dbg_lwip_tcp_rxtx_show(void);
|
||||
void dbg_lwip_udp_rxtx_show(void);
|
||||
void dbg_lwip_mem_cnt_show(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -71,8 +71,25 @@ extern const struct memp_desc* const memp_pools[MEMP_MAX];
|
|||
#include "lwip/mem.h"
|
||||
|
||||
#define memp_init()
|
||||
#if ESP_CNT_DEBUG
|
||||
static inline void* memp_malloc(int type)
|
||||
{
|
||||
ESP_CNT_MEM_MALLOC_INC(type);
|
||||
return mem_malloc(memp_pools[type]->size);
|
||||
}
|
||||
|
||||
static inline void memp_free(int type, void *mem)
|
||||
{
|
||||
ESP_CNT_MEM_FREE_INC(type);
|
||||
mem_free(mem);
|
||||
}
|
||||
|
||||
//#define memp_malloc(type) mem_malloc(memp_pools[type]->size); ESP_CNT_MEM_MALLOC_INC(type)
|
||||
//#define memp_free(type, mem) mem_free(mem); ESP_CNT_MEM_FREE_INC(type)
|
||||
#else
|
||||
#define memp_malloc(type) mem_malloc(memp_pools[type]->size)
|
||||
#define memp_free(type, mem) mem_free(mem)
|
||||
#endif
|
||||
|
||||
#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
|
||||
const struct memp_desc memp_ ## name = { \
|
||||
|
|
|
@ -352,6 +352,10 @@ err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
|
|||
void nd6_reachability_hint(const ip6_addr_t * ip6addr);
|
||||
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
|
||||
|
||||
#if ESP_LWIP
|
||||
/** set nd6 callback when ipv6 addr state pref*/
|
||||
void nd6_set_cb(struct netif *netif, void (*cb)(struct netif *netif, u8_t ip_index));
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -190,11 +190,6 @@ struct netif {
|
|||
/** pointer to next in linked list */
|
||||
struct netif *next;
|
||||
|
||||
#if ESP_LWIP
|
||||
//ip_addr_t is changed by marco IPV4, IPV6
|
||||
ip_addr_t link_local_addr;
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV4
|
||||
/** IP address configuration in network byte order */
|
||||
ip_addr_t ip_addr;
|
||||
|
@ -207,6 +202,10 @@ struct netif {
|
|||
/** The state of each IPv6 address (Tentative, Preferred, etc).
|
||||
* @see ip6_addr.h */
|
||||
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
|
||||
#if ESP_LWIP
|
||||
void (*ipv6_addr_cb)(struct netif* netif, u8_t ip_idex); /* callback for ipv6 addr states changed */
|
||||
#endif
|
||||
|
||||
#endif /* LWIP_IPV6 */
|
||||
/** This function is called by the network device driver
|
||||
* to pass a packet up the TCP/IP stack. */
|
||||
|
|
|
@ -140,6 +140,16 @@ struct memp_desc {
|
|||
#endif /* MEMP_MEM_MALLOC */
|
||||
};
|
||||
|
||||
#if (ESP_CNT_DEBUG == 1)
|
||||
extern uint32_t g_lwip_mem_cnt[MEMP_MAX][2];
|
||||
#define ESP_CNT_MEM_MALLOC_INC(type) g_lwip_mem_cnt[type][0]++
|
||||
#define ESP_CNT_MEM_FREE_INC(type) g_lwip_mem_cnt[type][1]++
|
||||
#else
|
||||
#define ESP_CNT_MEM_MALLOC_INC(type)
|
||||
#define ESP_CNT_MEM_FREE_INC(type)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LWIP_DEBUG
|
||||
#define DECLARE_LWIP_MEMPOOL_DESC(desc) (desc),
|
||||
#else
|
||||
|
|
|
@ -65,8 +65,8 @@
|
|||
*/
|
||||
#define SMEMCPY(dst,src,len) memcpy(dst,src,len)
|
||||
|
||||
extern unsigned long os_random(void);
|
||||
#define LWIP_RAND rand
|
||||
#define LWIP_RAND rand
|
||||
|
||||
/*
|
||||
------------------------------------
|
||||
---------- Memory options ----------
|
||||
|
@ -200,13 +200,35 @@ extern unsigned long os_random(void);
|
|||
*/
|
||||
#define LWIP_DHCP 1
|
||||
|
||||
#define DHCP_MAXRTX 0
|
||||
|
||||
#define DHCP_MAXRTX 0 //(*(volatile uint32*)0x600011E0)
|
||||
/*
|
||||
------------------------------------
|
||||
---------- AUTOIP options ----------
|
||||
------------------------------------
|
||||
*/
|
||||
#if CONFIG_MDNS
|
||||
/**
|
||||
* LWIP_AUTOIP==1: Enable AUTOIP module.
|
||||
*/
|
||||
#define LWIP_AUTOIP 1
|
||||
|
||||
/**
|
||||
* LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on
|
||||
* the same interface at the same time.
|
||||
*/
|
||||
#define LWIP_DHCP_AUTOIP_COOP 1
|
||||
|
||||
/**
|
||||
* LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes
|
||||
* that should be sent before falling back on AUTOIP. This can be set
|
||||
* as low as 1 to get an AutoIP address very quickly, but you should
|
||||
* be prepared to handle a changing IP address when DHCP overrides
|
||||
* AutoIP.
|
||||
*/
|
||||
#define LWIP_DHCP_AUTOIP_COOP_TRIES 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
----------------------------------
|
||||
---------- SNMP options ----------
|
||||
|
@ -308,6 +330,19 @@ extern unsigned long os_random(void);
|
|||
---------- LOOPIF options ----------
|
||||
------------------------------------
|
||||
*/
|
||||
#if CONFIG_MDNS
|
||||
/**
|
||||
* LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP
|
||||
* address equal to the netif IP address, looping them back up the stack.
|
||||
*/
|
||||
#define LWIP_NETIF_LOOPBACK 1
|
||||
|
||||
/**
|
||||
* LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback
|
||||
* sending for each netif (0 = disabled)
|
||||
*/
|
||||
#define LWIP_LOOPBACK_MAX_PBUFS 8
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------
|
||||
|
@ -414,6 +449,15 @@ extern unsigned long os_random(void);
|
|||
*/
|
||||
#define SO_REUSE CONFIG_LWIP_SO_REUSE
|
||||
|
||||
#if CONFIG_MDNS
|
||||
/**
|
||||
* SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets
|
||||
* to all local matches if SO_REUSEADDR is turned on.
|
||||
* WARNING: Adds a memcpy for every packet if passing to more than one pcb!
|
||||
*/
|
||||
#define SO_REUSE_RXTOALL 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
----------------------------------------
|
||||
---------- Statistics options ----------
|
||||
|
@ -515,6 +559,7 @@ extern unsigned long os_random(void);
|
|||
/* Enable all Espressif-only options */
|
||||
|
||||
#define ESP_LWIP 1
|
||||
#define ESP_LWIP_ARP 1
|
||||
#define ESP_PER_SOC_TCP_WND 1
|
||||
#define ESP_THREAD_SAFE 1
|
||||
#define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF
|
||||
|
@ -526,6 +571,7 @@ extern unsigned long os_random(void);
|
|||
#define ESP_IP4_ATON 1
|
||||
#define ESP_LIGHT_SLEEP 1
|
||||
#define ESP_L2_TO_L3_COPY CONFIG_L2_TO_L3_COPY
|
||||
#define ESP_CNT_DEBUG 0
|
||||
|
||||
#define TCP_WND_DEFAULT (4*TCP_MSS)
|
||||
#define TCP_SND_BUF_DEFAULT (2*TCP_MSS)
|
||||
|
|
|
@ -1192,11 +1192,28 @@ etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
|
|||
}
|
||||
#if ARP_QUEUE_LEN
|
||||
if (qlen >= ARP_QUEUE_LEN) {
|
||||
#if ESP_LWIP_ARP
|
||||
int l;
|
||||
struct etharp_q_entry *r;
|
||||
|
||||
l = qlen - 1;
|
||||
r = arp_table[i].q;
|
||||
while (l--)
|
||||
r = r->next;
|
||||
r->next = NULL;
|
||||
|
||||
pbuf_free(new_entry->p);
|
||||
memp_free(MEMP_ARP_QUEUE, new_entry);
|
||||
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue the packet %p (queue is full)\n", (void *)q));
|
||||
return ERR_MEM;
|
||||
#else
|
||||
struct etharp_q_entry *old;
|
||||
old = arp_table[i].q;
|
||||
arp_table[i].q = arp_table[i].q->next;
|
||||
pbuf_free(old->p);
|
||||
memp_free(MEMP_ARP_QUEUE, old);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
|
||||
|
|
|
@ -118,37 +118,29 @@ low_level_init(struct netif *netif)
|
|||
static err_t
|
||||
low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
wifi_interface_t wifi_if = tcpip_adapter_get_wifi_if(netif);
|
||||
wifi_interface_t wifi_if = tcpip_adapter_get_wifi_if(netif);
|
||||
struct pbuf *q = p;
|
||||
err_t ret;
|
||||
|
||||
if (wifi_if >= WIFI_IF_MAX) {
|
||||
return ERR_IF;
|
||||
}
|
||||
if (wifi_if >= WIFI_IF_MAX) {
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
#if ESP_LWIP
|
||||
q = p;
|
||||
u16_t pbuf_x_len = 0;
|
||||
pbuf_x_len = q->len;
|
||||
if(q->next !=NULL)
|
||||
{
|
||||
//char cnt = 0;
|
||||
struct pbuf *tmp = q->next;
|
||||
while(tmp != NULL)
|
||||
{
|
||||
memcpy( (u8_t *)( (u8_t *)(q->payload) + pbuf_x_len), (u8_t *)tmp->payload , tmp->len );
|
||||
pbuf_x_len += tmp->len;
|
||||
//cnt++;
|
||||
tmp = tmp->next;
|
||||
if(q->next == NULL) {
|
||||
ret = esp_wifi_internal_tx(wifi_if, q->payload, q->len);
|
||||
} else {
|
||||
LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
|
||||
q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
|
||||
if (q != NULL) {
|
||||
pbuf_copy(q, p);
|
||||
} else {
|
||||
return ERR_MEM;
|
||||
}
|
||||
ret = esp_wifi_internal_tx(wifi_if, q->payload, q->len);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
return esp_wifi_internal_tx(wifi_if, q->payload, pbuf_x_len);
|
||||
#else
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
esp_wifi_internal_tx(wifi_if, q->payload, q->len);
|
||||
}
|
||||
return ERR_OK;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ config MBEDTLS_SSL_MAX_CONTENT_LEN
|
|||
|
||||
config MBEDTLS_DEBUG
|
||||
bool "Enable mbedTLS debugging"
|
||||
default "no"
|
||||
default n
|
||||
help
|
||||
Enable mbedTLS debugging functions.
|
||||
|
||||
|
@ -34,4 +34,51 @@ config MBEDTLS_DEBUG
|
|||
functionality. See the "https_request_main" example for a
|
||||
sample function which connects the two together.
|
||||
|
||||
config MBEDTLS_HARDWARE_AES
|
||||
bool "Enable hardware AES acceleration"
|
||||
default y
|
||||
help
|
||||
Enable hardware accelerated AES encryption & decryption.
|
||||
|
||||
config MBEDTLS_HARDWARE_MPI
|
||||
bool "Enable hardware MPI (bignum) acceleration"
|
||||
default y
|
||||
help
|
||||
Enable hardware accelerated multiple precision integer operations.
|
||||
|
||||
Hardware accelerated multiplication, modulo multiplication,
|
||||
and modular exponentiation for up to 4096 bit results.
|
||||
|
||||
These operations are used by RSA.
|
||||
|
||||
config MBEDTLS_MPI_USE_INTERRUPT
|
||||
bool "Use interrupt for MPI operations"
|
||||
depends on MBEDTLS_HARDWARE_MPI
|
||||
default y
|
||||
help
|
||||
Use an interrupt to coordinate MPI operations.
|
||||
|
||||
This allows other code to run on the CPU while an MPI operation is pending.
|
||||
Otherwise the CPU busy-waits.
|
||||
|
||||
config MBEDTLS_MPI_INTERRUPT_NUM
|
||||
int "MPI Interrupt number"
|
||||
depends on MBEDTLS_MPI_USE_INTERRUPT
|
||||
default 18
|
||||
help
|
||||
CPU interrupt number for MPI interrupt to connect to. Must be otherwise unused.
|
||||
Eventually this assignment will be handled automatically at runtime.
|
||||
|
||||
config MBEDTLS_HARDWARE_SHA
|
||||
bool "Enable hardware SHA acceleration"
|
||||
default y
|
||||
help
|
||||
Enable hardware accelerated SHA1, SHA256, SHA384 & SHA512 in mbedTLS.
|
||||
|
||||
Due to a hardware limitation, hardware acceleration is only
|
||||
guaranteed if SHA digests are calculated one at a time. If more
|
||||
than one SHA digest is calculated at the same time, only will
|
||||
be calculated fully in hardware and the rest will be calculated
|
||||
(at least partially calculated) in software.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -5,4 +5,3 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := port/include include
|
||||
|
||||
COMPONENT_SRCDIRS := library port
|
||||
|
||||
|
|
|
@ -1092,6 +1092,8 @@ int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint
|
|||
return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
|
||||
}
|
||||
|
||||
#if !defined(MBEDTLS_MPI_MUL_MPI_ALT) || !defined(MBEDTLS_MPI_EXP_MOD_ALT)
|
||||
|
||||
/*
|
||||
* Helper for mbedtls_mpi multiplication
|
||||
*/
|
||||
|
@ -1103,6 +1105,7 @@ static
|
|||
*/
|
||||
__attribute__ ((noinline))
|
||||
#endif
|
||||
|
||||
void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
|
||||
{
|
||||
mbedtls_mpi_uint c = 0, t = 0;
|
||||
|
@ -1164,6 +1167,8 @@ void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mp
|
|||
while( c != 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(MBEDTLS_MPI_MUL_MPI_ALT)
|
||||
/*
|
||||
* Baseline multiplication: X = A * B (HAC 14.12)
|
||||
|
@ -1526,6 +1531,8 @@ int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_
|
|||
return( 0 );
|
||||
}
|
||||
|
||||
#if !defined(MBEDTLS_MPI_EXP_MOD_ALT)
|
||||
|
||||
/*
|
||||
* Fast Montgomery initialization (thanks to Tom St Denis)
|
||||
*/
|
||||
|
@ -1600,7 +1607,6 @@ static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint m
|
|||
return( mpi_montmul( A, &U, N, mm, T ) );
|
||||
}
|
||||
|
||||
#if !defined(MBEDTLS_MPI_EXP_MOD_ALT)
|
||||
/*
|
||||
* Sliding-window exponentiation: X = A^E mod N (HAC 14.85)
|
||||
*/
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue