forked from espressif/esp-idf
Merge branch 'cherry-pick-into-3.0' into 'release/v3.0'
Cherry pick into 3.0 See merge request !1714
This commit is contained in:
34
.editorconfig
Normal file
34
.editorconfig
Normal file
@@ -0,0 +1,34 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{*.md,*.rst}]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{Makefile,*.mk,*.bat}]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*/freertos/**]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[{*/freertos/**.S,**/FreeRTOSConfig.h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.pem]
|
||||
insert_final_newline = false
|
||||
|
||||
[*.py]
|
||||
max_line_length = 119
|
@@ -751,6 +751,13 @@ UT_003_08:
|
||||
- UT_T1_1
|
||||
- UT_single_core
|
||||
|
||||
UT_003_09:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_1
|
||||
- UT_single_core
|
||||
|
||||
UT_004_01:
|
||||
<<: *unit_test_template
|
||||
tags:
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "bootloader_config.h"
|
||||
#include "bootloader_clock.h"
|
||||
|
||||
#include "flash_qio_mode.h"
|
||||
|
||||
@@ -75,7 +76,6 @@ static void set_cache_and_start_app(uint32_t drom_addr,
|
||||
static void update_flash_config(const esp_image_header_t* pfhdr);
|
||||
static void vddsdio_configure();
|
||||
static void flash_gpio_configure();
|
||||
static void clock_configure(void);
|
||||
static void uart_console_configure(void);
|
||||
static void wdt_reset_check(void);
|
||||
|
||||
@@ -447,7 +447,7 @@ void bootloader_main()
|
||||
{
|
||||
vddsdio_configure();
|
||||
flash_gpio_configure();
|
||||
clock_configure();
|
||||
bootloader_clock_configure();
|
||||
uart_console_configure();
|
||||
wdt_reset_check();
|
||||
ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
|
||||
@@ -796,24 +796,20 @@ static void IRAM_ATTR flash_gpio_configure()
|
||||
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
|
||||
// For ESP32D2WD the SPI pins are already configured
|
||||
ESP_LOGI(TAG, "Detected ESP32D2WD");
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
||||
// For ESP32PICOD2 the SPI pins are already configured
|
||||
ESP_LOGI(TAG, "Detected ESP32PICOD2");
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
// For ESP32PICOD4 the SPI pins are already configured
|
||||
ESP_LOGI(TAG, "Detected ESP32PICOD4");
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Detected ESP32");
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
|
||||
gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
|
||||
@@ -839,46 +835,6 @@ static void IRAM_ATTR flash_gpio_configure()
|
||||
}
|
||||
}
|
||||
|
||||
static void clock_configure(void)
|
||||
{
|
||||
// ROM bootloader may have put a lot of text into UART0 FIFO.
|
||||
// Wait for it to be printed.
|
||||
// This is not needed on power on reset, when ROM bootloader is running at
|
||||
// 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
|
||||
// and will be done with the bootloader much earlier than UART FIFO is empty.
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
/* Set CPU to 80MHz. Keep other clocks unmodified. */
|
||||
rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
|
||||
|
||||
/* On ESP32 rev 0, switching to 80MHz if clock was previously set to
|
||||
* 240 MHz may cause the chip to lock up (see section 3.5 of the errata
|
||||
* document). For rev. 0, switch to 240 instead if it was chosen in
|
||||
* menuconfig.
|
||||
*/
|
||||
uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
|
||||
cpu_freq = RTC_CPU_FREQ_240M;
|
||||
}
|
||||
|
||||
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
||||
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
|
||||
clk_cfg.cpu_freq = cpu_freq;
|
||||
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
|
||||
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
|
||||
rtc_clk_init(clk_cfg);
|
||||
/* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
|
||||
* it here. Usually it needs some time to start up, so we amortize at least
|
||||
* part of the start up time by enabling 32k XTAL early.
|
||||
* App startup code will wait until the oscillator has started up.
|
||||
*/
|
||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
if (!rtc_clk_32k_enabled()) {
|
||||
rtc_clk_32k_bootstrap();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_console_configure(void)
|
||||
{
|
||||
|
21
components/bootloader_support/include/bootloader_clock.h
Normal file
21
components/bootloader_support/include/bootloader_clock.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @brief Configure clocks for early boot
|
||||
*
|
||||
* Called by bootloader, or by the app if the bootloader version is old (pre v2.1).
|
||||
*/
|
||||
void bootloader_clock_configure(void);
|
61
components/bootloader_support/src/bootloader_clock.c
Normal file
61
components/bootloader_support/src/bootloader_clock.c
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "rom/uart.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void bootloader_clock_configure()
|
||||
{
|
||||
// ROM bootloader may have put a lot of text into UART0 FIFO.
|
||||
// Wait for it to be printed.
|
||||
// This is not needed on power on reset, when ROM bootloader is running at
|
||||
// 40 MHz. But in case of TG WDT reset, CPU may still be running at >80 MHZ,
|
||||
// and will be done with the bootloader much earlier than UART FIFO is empty.
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
/* Set CPU to 80MHz. Keep other clocks unmodified. */
|
||||
rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
|
||||
|
||||
/* On ESP32 rev 0, switching to 80MHz if clock was previously set to
|
||||
* 240 MHz may cause the chip to lock up (see section 3.5 of the errata
|
||||
* document). For rev. 0, switch to 240 instead if it was chosen in
|
||||
* menuconfig.
|
||||
*/
|
||||
uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
|
||||
cpu_freq = RTC_CPU_FREQ_240M;
|
||||
}
|
||||
|
||||
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
||||
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
|
||||
clk_cfg.cpu_freq = cpu_freq;
|
||||
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
|
||||
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
|
||||
rtc_clk_init(clk_cfg);
|
||||
/* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
|
||||
* it here. Usually it needs some time to start up, so we amortize at least
|
||||
* part of the start up time by enabling 32k XTAL early.
|
||||
* App startup code will wait until the oscillator has started up.
|
||||
*/
|
||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
if (!rtc_clk_32k_enabled()) {
|
||||
rtc_clk_32k_bootstrap();
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -25,8 +25,6 @@
|
||||
#include "esp_system.h"
|
||||
#endif
|
||||
|
||||
const char *TAG = "boot_rng";
|
||||
|
||||
void bootloader_fill_random(void *buffer, size_t length)
|
||||
{
|
||||
uint8_t *buffer_bytes = (uint8_t *)buffer;
|
||||
|
@@ -270,7 +270,7 @@ extern char *suboptarg; /* getsubopt(3) external variable */
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";
|
||||
//static const char rcsid[]="$Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $";
|
||||
#endif /* lint */
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
@@ -53,7 +52,7 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||
#define I2C_TIMEING_VAL_ERR_STR "i2c timing value error"
|
||||
#define I2C_ADDR_ERROR_STR "i2c null address error"
|
||||
#define I2C_DRIVER_NOT_INSTALL_ERR_STR "i2c driver not installed"
|
||||
#define I2C_SLAVE_BUFFER_LEN_ERR_STR "i2c buffer size too short for slave mode"
|
||||
#define I2C_SLAVE_BUFFER_LEN_ERR_STR "i2c buffer size too small for slave mode"
|
||||
#define I2C_EVT_QUEUE_ERR_STR "i2c evt queue error"
|
||||
#define I2C_SEM_ERR_STR "i2c semaphore error"
|
||||
#define I2C_BUF_ERR_STR "i2c ringbuffer error"
|
||||
@@ -65,13 +64,16 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 };
|
||||
#define I2C_SDA_IO_ERR_STR "sda gpio number error"
|
||||
#define I2C_SCL_IO_ERR_STR "scl gpio number error"
|
||||
#define I2C_CMD_LINK_INIT_ERR_STR "i2c command link error"
|
||||
#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin do not support internal pull-up"
|
||||
#define I2C_GPIO_PULLUP_ERR_STR "this i2c pin does not support internal pull-up"
|
||||
#define I2C_ACK_TYPE_ERR_STR "i2c ack type error"
|
||||
#define I2C_DATA_LEN_ERR_STR "i2c data read length error"
|
||||
#define I2C_FIFO_FULL_THRESH_VAL (28)
|
||||
#define I2C_FIFO_EMPTY_THRESH_VAL (5)
|
||||
#define I2C_IO_INIT_LEVEL (1)
|
||||
#define I2C_CMD_ALIVE_INTERVAL_TICK (1000 / portTICK_PERIOD_MS)
|
||||
#define I2C_CMD_EVT_ALIVE (BIT0)
|
||||
#define I2C_CMD_EVT_DONE (BIT1)
|
||||
#define I2C_CMD_EVT_ALIVE (0)
|
||||
#define I2C_CMD_EVT_DONE (1)
|
||||
#define I2C_EVT_QUEUE_LEN (1)
|
||||
#define I2C_SLAVE_TIMEOUT_DEFAULT (32000) /* I2C slave timeout value, APB clock cycle number */
|
||||
#define I2C_SLAVE_SDA_SAMPLE_DEFAULT (10) /* I2C slave sample time after scl positive edge default value */
|
||||
#define I2C_SLAVE_SDA_HOLD_DEFAULT (10) /* I2C slave hold time after scl negative edge default value */
|
||||
@@ -107,6 +109,10 @@ typedef enum {
|
||||
I2C_STATUS_TIMEOUT, /*!< I2C bus status error, and operation timeout */
|
||||
} i2c_status_t;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
} i2c_cmd_evt_t;
|
||||
|
||||
typedef struct {
|
||||
int i2c_num; /*!< I2C port number */
|
||||
int mode; /*!< I2C mode, master or slave */
|
||||
@@ -117,7 +123,7 @@ typedef struct {
|
||||
uint8_t data_buf[I2C_FIFO_LEN]; /*!< a buffer to store i2c fifo data */
|
||||
|
||||
i2c_cmd_desc_t cmd_link; /*!< I2C command link */
|
||||
EventGroupHandle_t cmd_evt; /*!< I2C command event bits */
|
||||
QueueHandle_t cmd_evt_queue; /*!< I2C command event queue */
|
||||
xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */
|
||||
size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */
|
||||
size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */
|
||||
@@ -175,7 +181,7 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||
}
|
||||
p_i2c->rx_buf_length = slv_rx_buf_len;
|
||||
} else {
|
||||
p_i2c->tx_ring_buf = NULL;
|
||||
p_i2c->rx_ring_buf = NULL;
|
||||
p_i2c->rx_buf_length = 0;
|
||||
}
|
||||
if (slv_tx_buf_len > 0) {
|
||||
@@ -191,7 +197,7 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||
}
|
||||
p_i2c->slv_rx_mux = xSemaphoreCreateMutex();
|
||||
p_i2c->slv_tx_mux = xSemaphoreCreateMutex();
|
||||
if (p_i2c->slv_rx_mux == NULL || p_i2c->slv_rx_mux == NULL) {
|
||||
if (p_i2c->slv_rx_mux == NULL || p_i2c->slv_tx_mux == NULL) {
|
||||
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
|
||||
goto err;
|
||||
}
|
||||
@@ -199,8 +205,8 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||
} else {
|
||||
//semaphore to sync sending process, because we only have 32 bytes for hardware fifo.
|
||||
p_i2c->cmd_mux = xSemaphoreCreateMutex();
|
||||
p_i2c->cmd_evt = xEventGroupCreate();
|
||||
if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt == NULL) {
|
||||
p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));
|
||||
if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt_queue == NULL) {
|
||||
ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);
|
||||
goto err;
|
||||
}
|
||||
@@ -243,9 +249,9 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||
p_i2c_obj[i2c_num]->tx_ring_buf = NULL;
|
||||
p_i2c_obj[i2c_num]->tx_buf_length = 0;
|
||||
}
|
||||
if (p_i2c_obj[i2c_num]->cmd_evt) {
|
||||
vEventGroupDelete(p_i2c_obj[i2c_num]->cmd_evt);
|
||||
p_i2c_obj[i2c_num]->cmd_evt = NULL;
|
||||
if (p_i2c_obj[i2c_num]->cmd_evt_queue) {
|
||||
vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue);
|
||||
p_i2c_obj[i2c_num]->cmd_evt_queue = NULL;
|
||||
}
|
||||
if (p_i2c_obj[i2c_num]->cmd_mux) {
|
||||
vSemaphoreDelete(p_i2c_obj[i2c_num]->cmd_mux);
|
||||
@@ -258,6 +264,7 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
|
||||
}
|
||||
}
|
||||
free(p_i2c_obj[i2c_num]);
|
||||
p_i2c_obj[i2c_num] = NULL;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -296,9 +303,9 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
|
||||
xSemaphoreTake(p_i2c->cmd_mux, portMAX_DELAY);
|
||||
vSemaphoreDelete(p_i2c->cmd_mux);
|
||||
}
|
||||
if (p_i2c_obj[i2c_num]->cmd_evt) {
|
||||
vEventGroupDelete(p_i2c_obj[i2c_num]->cmd_evt);
|
||||
p_i2c_obj[i2c_num]->cmd_evt = NULL;
|
||||
if (p_i2c_obj[i2c_num]->cmd_evt_queue) {
|
||||
vQueueDelete(p_i2c_obj[i2c_num]->cmd_evt_queue);
|
||||
p_i2c_obj[i2c_num]->cmd_evt_queue = NULL;
|
||||
}
|
||||
if (p_i2c->slv_rx_mux) {
|
||||
vSemaphoreDelete(p_i2c->slv_rx_mux);
|
||||
@@ -437,7 +444,9 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
|
||||
}
|
||||
}
|
||||
if (p_i2c->mode == I2C_MODE_MASTER) {
|
||||
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE, &HPTaskAwoken);
|
||||
i2c_cmd_evt_t evt;
|
||||
evt.type = I2C_CMD_EVT_ALIVE;
|
||||
xQueueSendFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
|
||||
if (HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
@@ -651,8 +660,10 @@ esp_err_t i2c_set_start_timing(i2c_port_t i2c_num, int setup_time, int hold_time
|
||||
I2C_CHECK((hold_time <= I2C_SCL_START_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((setup_time <= I2C_SCL_RSTART_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_start_hold.time = hold_time;
|
||||
I2C[i2c_num]->scl_rstart_setup.time = setup_time;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -676,8 +687,10 @@ esp_err_t i2c_set_stop_timing(i2c_port_t i2c_num, int setup_time, int hold_time)
|
||||
I2C_CHECK((setup_time <= I2C_SCL_STOP_SETUP_TIME_V) && (setup_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((hold_time <= I2C_SCL_STOP_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->scl_stop_hold.time = hold_time;
|
||||
I2C[i2c_num]->scl_stop_setup.time = setup_time;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -701,8 +714,10 @@ esp_err_t i2c_set_data_timing(i2c_port_t i2c_num, int sample_time, int hold_time
|
||||
I2C_CHECK((sample_time <= I2C_SDA_SAMPLE_TIME_V) && (sample_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((hold_time <= I2C_SDA_HOLD_TIME_V) && (hold_time > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->sda_hold.time = hold_time;
|
||||
I2C[i2c_num]->sda_sample.time = sample_time;
|
||||
I2C_EXIT_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -723,7 +738,7 @@ esp_err_t i2c_get_data_timing(i2c_port_t i2c_num, int* sample_time, int* hold_ti
|
||||
esp_err_t i2c_set_timeout(i2c_port_t i2c_num, int timeout)
|
||||
{
|
||||
I2C_CHECK(i2c_num < I2C_NUM_MAX, I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((timeout <= I2C_SDA_SAMPLE_TIME_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK((timeout <= I2C_TIME_OUT_REG_V) && (timeout > 0), I2C_TIMEING_VAL_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
I2C_ENTER_CRITICAL(&i2c_spinlock[i2c_num]);
|
||||
I2C[i2c_num]->timeout.tout = timeout;
|
||||
@@ -945,11 +960,8 @@ esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool
|
||||
return i2c_cmd_link_append(cmd_handle, &cmd);
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, int ack)
|
||||
static esp_err_t i2c_master_read_static(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack)
|
||||
{
|
||||
I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
int len_tmp;
|
||||
int data_offset = 0;
|
||||
esp_err_t ret;
|
||||
@@ -972,25 +984,49 @@ esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t dat
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, int ack)
|
||||
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_ack_type_t ack)
|
||||
{
|
||||
I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
i2c_cmd_t cmd;
|
||||
cmd.ack_en = 0;
|
||||
cmd.ack_exp = 0;
|
||||
cmd.ack_val = ack & 0x1;
|
||||
cmd.ack_val = ((ack == I2C_MASTER_LAST_NACK) ? I2C_MASTER_NACK : (ack & 0x1));
|
||||
cmd.byte_num = 1;
|
||||
cmd.op_code = I2C_CMD_READ;
|
||||
cmd.data = data;
|
||||
return i2c_cmd_link_append(cmd_handle, &cmd);
|
||||
}
|
||||
|
||||
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack)
|
||||
{
|
||||
I2C_CHECK((data != NULL), I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(ack < I2C_MASTER_ACK_MAX, I2C_ACK_TYPE_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
I2C_CHECK(data_len < 1, I2C_DATA_LEN_ERR_STR, ESP_ERR_INVALID_ARG);
|
||||
|
||||
if(ack != I2C_MASTER_LAST_NACK) {
|
||||
return i2c_master_read_static(cmd_handle, data, data_len, ack);
|
||||
} else {
|
||||
if(data_len == 1) {
|
||||
return i2c_master_read_byte(cmd_handle, data, I2C_MASTER_NACK);
|
||||
} else {
|
||||
esp_err_t ret;
|
||||
if((ret = i2c_master_read_static(cmd_handle, data, data_len - 1, I2C_MASTER_ACK)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
return i2c_master_read_byte(cmd_handle, data + data_len - 1, I2C_MASTER_NACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
||||
{
|
||||
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
|
||||
i2c_cmd_evt_t evt;
|
||||
//This should never happen
|
||||
if (p_i2c->mode == I2C_MODE_SLAVE) {
|
||||
return;
|
||||
@@ -1005,7 +1041,8 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
||||
I2C[i2c_num]->int_clr.time_out = 1;
|
||||
I2C[i2c_num]->int_ena.val = 0;
|
||||
}
|
||||
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_DONE, &HPTaskAwoken);
|
||||
evt.type = I2C_CMD_EVT_DONE;
|
||||
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
|
||||
if (HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
@@ -1024,7 +1061,8 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
|
||||
}
|
||||
if (p_i2c->cmd_link.head == NULL) {
|
||||
p_i2c->cmd_link.cur = NULL;
|
||||
xEventGroupSetBitsFromISR(p_i2c->cmd_evt, I2C_CMD_EVT_DONE, &HPTaskAwoken);
|
||||
evt.type = I2C_CMD_EVT_DONE;
|
||||
xQueueOverwriteFromISR(p_i2c->cmd_evt_queue, &evt, &HPTaskAwoken);
|
||||
if (HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
@@ -1103,12 +1141,12 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_obj_t* p_i2c = p_i2c_obj[i2c_num];
|
||||
portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
|
||||
portTickType ticks_start = xTaskGetTickCount();
|
||||
portBASE_TYPE res = xSemaphoreTake(p_i2c->cmd_mux, ticks_to_wait);
|
||||
if (res == pdFALSE) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_DONE | I2C_CMD_EVT_ALIVE);
|
||||
xQueueReset(p_i2c->cmd_evt_queue);
|
||||
if (p_i2c->status == I2C_STATUS_TIMEOUT
|
||||
|| I2C[i2c_num]->status_reg.bus_busy == 1) {
|
||||
i2c_hw_fsm_reset(i2c_num);
|
||||
@@ -1129,24 +1167,25 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||
|
||||
//start send commands, at most 32 bytes one time, isr handler will process the remaining commands.
|
||||
i2c_master_cmd_begin_static(i2c_num);
|
||||
if (ticks_to_wait == portMAX_DELAY) {
|
||||
|
||||
} else if (ticks_to_wait == 0) {
|
||||
|
||||
} else {
|
||||
ticks_to_wait = ticks_end - xTaskGetTickCount();
|
||||
}
|
||||
// Wait event bits
|
||||
EventBits_t uxBits;
|
||||
i2c_cmd_evt_t evt;
|
||||
while (1) {
|
||||
TickType_t wait_time = (ticks_to_wait < (I2C_CMD_ALIVE_INTERVAL_TICK) ? ticks_to_wait : (I2C_CMD_ALIVE_INTERVAL_TICK));
|
||||
TickType_t wait_time = xTaskGetTickCount();
|
||||
if (wait_time - ticks_start > ticks_to_wait) { // out of time
|
||||
wait_time = I2C_CMD_ALIVE_INTERVAL_TICK;
|
||||
} else {
|
||||
wait_time = ticks_to_wait - (wait_time - ticks_start);
|
||||
if (wait_time < I2C_CMD_ALIVE_INTERVAL_TICK) {
|
||||
wait_time = I2C_CMD_ALIVE_INTERVAL_TICK;
|
||||
}
|
||||
}
|
||||
// In master mode, since we don't have an interrupt to detective bus error or FSM state, what we do here is to make
|
||||
// sure the interrupt mechanism for master mode is still working.
|
||||
// If the command sending is not finished and there is no interrupt any more, the bus is probably dead caused by external noise.
|
||||
uxBits = xEventGroupWaitBits(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE | I2C_CMD_EVT_DONE, false, false, wait_time);
|
||||
if (uxBits) {
|
||||
if (uxBits & I2C_CMD_EVT_DONE) {
|
||||
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_DONE);
|
||||
portBASE_TYPE evt_res = xQueueReceive(p_i2c->cmd_evt_queue, &evt, wait_time);
|
||||
if (evt_res == pdTRUE) {
|
||||
if (evt.type == I2C_CMD_EVT_DONE) {
|
||||
if (p_i2c->status == I2C_STATUS_TIMEOUT) {
|
||||
// If the I2C slave are powered off or the SDA/SCL are connected to ground, for example,
|
||||
// I2C hw FSM would get stuck in wrong state, we have to reset the I2C module in this case.
|
||||
@@ -1159,8 +1198,7 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (uxBits & I2C_CMD_EVT_ALIVE) {
|
||||
xEventGroupClearBits(p_i2c->cmd_evt, I2C_CMD_EVT_ALIVE);
|
||||
if (evt.type == I2C_CMD_EVT_ALIVE) {
|
||||
}
|
||||
} else {
|
||||
ret = ESP_ERR_TIMEOUT;
|
||||
@@ -1169,12 +1207,6 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
|
||||
i2c_hw_fsm_reset(i2c_num);
|
||||
break;
|
||||
}
|
||||
if (ticks_to_wait == portMAX_DELAY) {
|
||||
|
||||
} else {
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
ticks_to_wait = ticks_end > now ? (ticks_end - now) : 0;
|
||||
}
|
||||
}
|
||||
p_i2c->status = I2C_STATUS_DONE;
|
||||
xSemaphoreGive(p_i2c->cmd_mux);
|
||||
@@ -1252,6 +1284,3 @@ int i2c_slave_read_buffer(i2c_port_t i2c_num, uint8_t* data, size_t max_size, Ti
|
||||
xSemaphoreGive(p_i2c->slv_rx_mux);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -69,6 +69,13 @@ typedef enum {
|
||||
I2C_ADDR_BIT_MAX,
|
||||
} i2c_addr_mode_t;
|
||||
|
||||
typedef enum {
|
||||
I2C_MASTER_ACK = 0x0, /*!< I2C ack for each byte read */
|
||||
I2C_MASTER_NACK = 0x1, /*!< I2C nack for each byte read */
|
||||
I2C_MASTER_LAST_NACK = 0x2, /*!< I2C nack for the last byte*/
|
||||
I2C_MASTER_ACK_MAX,
|
||||
} i2c_ack_type_t;
|
||||
|
||||
/**
|
||||
* @brief I2C initialization parameters
|
||||
*/
|
||||
@@ -288,7 +295,7 @@ esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t da
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, int ack);
|
||||
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_ack_type_t ack);
|
||||
|
||||
/**
|
||||
* @brief Queue command for I2C master to read data from I2C bus
|
||||
@@ -305,7 +312,7 @@ esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, int a
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, int ack);
|
||||
esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t data_len, i2c_ack_type_t ack);
|
||||
|
||||
/**
|
||||
* @brief Queue command for I2C master to generate a stop signal
|
||||
|
@@ -51,7 +51,7 @@ typedef enum {
|
||||
}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_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;
|
||||
@@ -84,10 +84,10 @@ typedef enum {
|
||||
* @brief Data struct of RMT TX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool loop_en; /*!< RMT loop output mode*/
|
||||
bool loop_en; /*!< Enable sending RMT items in a loop */
|
||||
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 */
|
||||
rmt_carrier_level_t carrier_level; /*!< Level of the RMT output, when the carrier is applied */
|
||||
bool carrier_en; /*!< RMT carrier enable */
|
||||
rmt_idle_level_t idle_level; /*!< RMT idle level */
|
||||
bool idle_output_en; /*!< RMT idle level output enable */
|
||||
@@ -97,7 +97,7 @@ typedef struct {
|
||||
* @brief Data struct of RMT RX configure parameters
|
||||
*/
|
||||
typedef struct {
|
||||
bool filter_en; /*!< RMT receiver filer enable*/
|
||||
bool filter_en; /*!< RMT receiver filter enable */
|
||||
uint8_t filter_ticks_thresh; /*!< RMT filter tick number */
|
||||
uint16_t idle_threshold; /*!< RMT RX idle threshold */
|
||||
}rmt_rx_config_t;
|
||||
@@ -186,10 +186,12 @@ esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh);
|
||||
* 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.
|
||||
@@ -233,10 +235,8 @@ esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num);
|
||||
* @param low_level Low level duration of carrier.
|
||||
*
|
||||
* @param carrier_level Configure the way carrier wave is modulated for channel 0-7.
|
||||
*
|
||||
* 1'b1:transmit on low output level
|
||||
*
|
||||
* 1'b0:transmit on high output level
|
||||
* - 1'b1:transmit on low output level
|
||||
* - 1'b0:transmit on high output level
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@@ -364,10 +364,9 @@ esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner);
|
||||
*
|
||||
* @param channel RMT channel (0-7)
|
||||
*
|
||||
* @param loop_en To enable RMT transmitter loop sending mode.
|
||||
*
|
||||
* @param loop_en Enable RMT transmitter loop sending mode.
|
||||
* If set true, transmitter will continue sending from the first data
|
||||
* to the last data in channel0-7 again and again.
|
||||
* to the last data in channel 0-7 over and over again in a loop.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@@ -409,7 +408,7 @@ esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t th
|
||||
/**
|
||||
* @brief Set RMT source clock
|
||||
*
|
||||
* RMT module has two source clock:
|
||||
* RMT module has two clock sources:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz (not supported in this version).
|
||||
*
|
||||
@@ -426,7 +425,7 @@ 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:
|
||||
* RMT module has two clock sources:
|
||||
* 1. APB clock which is 80Mhz
|
||||
* 2. REF tick clock, which would be 1Mhz (not supported in this version).
|
||||
*
|
||||
@@ -526,7 +525,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
|
||||
/**
|
||||
* @brief Set RMT TX threshold event interrupt enable
|
||||
*
|
||||
* Causes an interrupt when a threshold number of items have been transmitted.
|
||||
* An interrupt will be triggered when the number of transmitted items reaches the threshold value
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
@@ -541,7 +540,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en);
|
||||
esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh);
|
||||
|
||||
/**
|
||||
* @brief Set RMT pins
|
||||
* @brief Set RMT pin
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
@@ -558,7 +557,7 @@ esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_nu
|
||||
/**
|
||||
* @brief Configure RMT parameters
|
||||
*
|
||||
* @param rmt_param RMT parameter structor
|
||||
* @param rmt_param RMT parameter struct
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@@ -567,14 +566,15 @@ esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_nu
|
||||
esp_err_t rmt_config(const rmt_config_t* rmt_param);
|
||||
|
||||
/**
|
||||
* @brief register RMT interrupt handler, the handler is an ISR.
|
||||
* @brief Register RMT interrupt handler, the handler is an ISR.
|
||||
*
|
||||
* The handler will be attached to the same CPU core that this function is running on.
|
||||
*
|
||||
* @note If you already called rmt_driver_install to use system RMT driver,
|
||||
* please do not register ISR handler again.
|
||||
*
|
||||
* @param fn Interrupt handler function.
|
||||
* @param arg Parameter for handler function
|
||||
* @param arg Parameter for the handler function
|
||||
* @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)
|
||||
* ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.
|
||||
* @param handle If non-zero, a handle to later clean up the ISR gets stored here.
|
||||
@@ -653,9 +653,9 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel);
|
||||
*
|
||||
* @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.
|
||||
* @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,
|
||||
@@ -677,24 +677,24 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t* rmt_item, i
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param wait_time Maximum time to wait for transmission to be complete
|
||||
* @param wait_time Maximum time in ticks to wait for transmission to be complete
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK RMT Tx done successfully
|
||||
* - ESP_ERR_TIMEOUT Crossed the 'wait_time' given
|
||||
* - ESP_ERR_TIMEOUT Exceeded the 'wait_time' given
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
* - ESP_FAIL Driver not installed
|
||||
*/
|
||||
esp_err_t rmt_wait_tx_done(rmt_channel_t channel, TickType_t wait_time);
|
||||
|
||||
/**
|
||||
* @brief Get ringbuffer from UART.
|
||||
* @brief Get ringbuffer from RMT.
|
||||
*
|
||||
* Users can get the RMT RX ringbuffer handler, and process the RX data.
|
||||
* Users can get the RMT RX ringbuffer handle, and process the RX data.
|
||||
*
|
||||
* @param channel RMT channel (0 - 7)
|
||||
*
|
||||
* @param buf_handle Pointer to buffer handler to accept RX ringbuffer handler.
|
||||
* @param buf_handle Pointer to buffer handle to accept RX ringbuffer handle.
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
@@ -702,62 +702,7 @@ esp_err_t rmt_wait_tx_done(rmt_channel_t channel, TickType_t wait_time);
|
||||
*/
|
||||
esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_handle);
|
||||
|
||||
/***************************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, 0);
|
||||
* }
|
||||
*
|
||||
* @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, 0);
|
||||
* }
|
||||
*
|
||||
/*
|
||||
* ----------------EXAMPLE OF RMT INTERRUPT ------------------
|
||||
* @code{c}
|
||||
*
|
||||
@@ -774,7 +719,7 @@ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_han
|
||||
* //read RMT interrupt status.
|
||||
* uint32_t intr_st = RMT.int_st.val;
|
||||
*
|
||||
* //you will find which channels have triggered fade_end interrupt here,
|
||||
* //you will find which channels have triggered an 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.
|
||||
*
|
||||
@@ -788,8 +733,6 @@ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_han
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -25,12 +25,12 @@
|
||||
#include "driver/sdspi_host.h"
|
||||
#include "sdspi_private.h"
|
||||
#include "sdspi_crc.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
|
||||
/// Max number of transactions in flight (used in start_command_write_blocks)
|
||||
#define SDSPI_TRANSACTION_COUNT 4
|
||||
#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high
|
||||
/// FIXME: this has to be replaced with a timeout expressed in ms, rather in retries
|
||||
#define SDSPI_RETRY_COUNT 1000
|
||||
#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused
|
||||
/// Size of the buffer returned by get_block_buf
|
||||
#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)
|
||||
@@ -426,7 +426,7 @@ static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd)
|
||||
}
|
||||
|
||||
// Wait until MISO goes high
|
||||
static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
||||
static esp_err_t poll_busy(int slot, spi_transaction_t* t, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx;
|
||||
*t = (spi_transaction_t) {
|
||||
@@ -436,7 +436,9 @@ static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
||||
};
|
||||
esp_err_t ret;
|
||||
|
||||
for (int i = 0; i < SDSPI_RETRY_COUNT; i++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
int nonzero_count = 0;
|
||||
do {
|
||||
t_rx = SDSPI_MOSI_IDLE_VAL;
|
||||
t->rx_data[0] = 0;
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
@@ -444,16 +446,17 @@ static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
||||
return ret;
|
||||
}
|
||||
if (t->rx_data[0] != 0) {
|
||||
if (i < SDSPI_RETRY_COUNT - 2) {
|
||||
i = SDSPI_RETRY_COUNT - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (++nonzero_count == 2) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
} while(esp_timer_get_time() < t_end);
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
// Wait for response token
|
||||
static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
||||
static esp_err_t poll_response_token(int slot, spi_transaction_t* t, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx;
|
||||
*t = (spi_transaction_t) {
|
||||
@@ -462,8 +465,8 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
||||
.length = 8,
|
||||
};
|
||||
esp_err_t ret;
|
||||
|
||||
for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
do {
|
||||
t_rx = SDSPI_MOSI_IDLE_VAL;
|
||||
t->rx_data[0] = 0;
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
@@ -471,7 +474,7 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
||||
return ret;
|
||||
}
|
||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_OK) {
|
||||
break;
|
||||
return ESP_OK;
|
||||
}
|
||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_CRC_ERR) {
|
||||
return ESP_ERR_INVALID_CRC;
|
||||
@@ -479,19 +482,17 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_WRITE_ERR) {
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
} while (esp_timer_get_time() < t_end);
|
||||
|
||||
return ESP_OK;
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
// Wait for data token, reading 8 bytes at a time.
|
||||
// If the token is found, write all subsequent bytes to extra_ptr,
|
||||
// and store the number of bytes written to extra_size.
|
||||
static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
||||
uint8_t* extra_ptr, size_t* extra_size)
|
||||
uint8_t* extra_ptr, size_t* extra_size, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx[8];
|
||||
*t = (spi_transaction_t) {
|
||||
@@ -500,7 +501,8 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
||||
.length = sizeof(t_rx) * 8,
|
||||
};
|
||||
esp_err_t ret;
|
||||
for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
do {
|
||||
memset(t_rx, SDSPI_MOSI_IDLE_VAL, sizeof(t_rx));
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
if (ret != ESP_OK) {
|
||||
@@ -522,14 +524,12 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
} while (esp_timer_get_time() < t_end);
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -608,11 +608,14 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
||||
if (need_poll) {
|
||||
// Wait for data to be ready
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size);
|
||||
ret = poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (extra_data_size) {
|
||||
extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
|
||||
}
|
||||
release_transaction(slot);
|
||||
}
|
||||
|
||||
// Arrange RX buffer
|
||||
@@ -674,14 +677,17 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
||||
// To end multi block transfer, send stop command and wait for the
|
||||
// card to process it
|
||||
sdspi_hw_cmd_t stop_cmd;
|
||||
make_hw_cmd(MMC_STOP_TRANSMISSION, 0, &stop_cmd);
|
||||
make_hw_cmd(MMC_STOP_TRANSMISSION, 0, cmd->timeout_ms, &stop_cmd);
|
||||
ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -768,7 +774,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
||||
|
||||
// Poll for response
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_response_token(slot, t_poll);
|
||||
ret = poll_response_token(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
@@ -776,7 +782,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
||||
|
||||
// Wait for the card to finish writing data
|
||||
t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
@@ -803,7 +809,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
||||
wait_for_transactions(slot);
|
||||
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
|
@@ -73,6 +73,8 @@ typedef struct {
|
||||
uint8_t r1;
|
||||
/// Up to 16 bytes of response. Luckily, this is aligned on 4 byte boundary.
|
||||
uint32_t response[4];
|
||||
/// response timeout, in milliseconds
|
||||
int timeout_ms;
|
||||
} sdspi_hw_cmd_t;
|
||||
|
||||
#define SDSPI_CMD_NORESP_SIZE 6 //!< Size of the command without any response
|
||||
@@ -90,7 +92,7 @@ typedef struct {
|
||||
|
||||
#define SDSPI_MAX_DATA_LEN 512 //!< Max size of single block transfer
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd);
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd);
|
||||
|
||||
esp_err_t sdspi_host_start_command(int slot, sdspi_hw_cmd_t *cmd,
|
||||
void *data, uint32_t data_size, int flags);
|
||||
|
@@ -36,7 +36,7 @@ static uint8_t sdspi_msg_crc7(sdspi_hw_cmd_t* hw_cmd)
|
||||
return sdspi_crc7((const uint8_t *)hw_cmd, bytes_to_crc);
|
||||
}
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd)
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd)
|
||||
{
|
||||
hw_cmd->start_bit = 0;
|
||||
hw_cmd->transmission_bit = 1;
|
||||
@@ -48,6 +48,7 @@ void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd)
|
||||
uint32_t arg_s = __builtin_bswap32(arg);
|
||||
memcpy(hw_cmd->arguments, &arg_s, sizeof(arg_s));
|
||||
hw_cmd->crc7 = sdspi_msg_crc7(hw_cmd);
|
||||
hw_cmd->timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
|
||||
@@ -55,7 +56,7 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
|
||||
_lock_acquire(&s_lock);
|
||||
// Convert the command to wire format
|
||||
sdspi_hw_cmd_t hw_cmd;
|
||||
make_hw_cmd(cmdinfo->opcode, cmdinfo->arg, &hw_cmd);
|
||||
make_hw_cmd(cmdinfo->opcode, cmdinfo->arg, cmdinfo->timeout_ms, &hw_cmd);
|
||||
|
||||
// Flags indicate which of the transfer types should be used
|
||||
int flags = 0;
|
||||
|
@@ -631,6 +631,10 @@ config BROWNOUT_DET_LVL
|
||||
default 7 if BROWNOUT_DET_LVL_SEL_7
|
||||
|
||||
|
||||
# Note about the use of "FRC1" name: currently FRC1 timer is not used for
|
||||
# high resolution timekeeping anymore. Instead the esp_timer API, implemented
|
||||
# using FRC2 timer, is used.
|
||||
# FRC1 name in the option name is kept for compatibility.
|
||||
choice ESP32_TIME_SYSCALL
|
||||
prompt "Timers used for gettimeofday function"
|
||||
default ESP32_TIME_SYSCALL_USE_RTC_FRC1
|
||||
@@ -638,12 +642,12 @@ choice ESP32_TIME_SYSCALL
|
||||
This setting defines which hardware timers are used to
|
||||
implement 'gettimeofday' and 'time' functions in C library.
|
||||
|
||||
- If only FRC1 timer is used, gettimeofday will provide time at
|
||||
microsecond resolution. Time will not be preserved when going
|
||||
into deep sleep mode.
|
||||
- If both FRC1 and RTC timers are used, timekeeping will
|
||||
- If both high-resolution and RTC timers are used, timekeeping will
|
||||
continue in deep sleep. Time will be reported at 1 microsecond
|
||||
resolution.
|
||||
resolution. This is the default, and the recommended option.
|
||||
- If only high-resolution timer is used, gettimeofday will
|
||||
provide time at microsecond resolution.
|
||||
Time will not be preserved when going into deep sleep mode.
|
||||
- If only RTC timer is used, timekeeping will continue in
|
||||
deep sleep, but time will be measured at 6.(6) microsecond
|
||||
resolution. Also the gettimeofday function itself may take
|
||||
@@ -653,12 +657,12 @@ choice ESP32_TIME_SYSCALL
|
||||
- When RTC is used for timekeeping, two RTC_STORE registers are
|
||||
used to keep time in deep sleep mode.
|
||||
|
||||
config ESP32_TIME_SYSCALL_USE_RTC_FRC1
|
||||
bool "RTC and high-resolution timer"
|
||||
config ESP32_TIME_SYSCALL_USE_RTC
|
||||
bool "RTC"
|
||||
config ESP32_TIME_SYSCALL_USE_RTC_FRC1
|
||||
bool "RTC and FRC1"
|
||||
config ESP32_TIME_SYSCALL_USE_FRC1
|
||||
bool "FRC1"
|
||||
bool "High-resolution timer"
|
||||
config ESP32_TIME_SYSCALL_USE_NONE
|
||||
bool "None"
|
||||
endchoice
|
||||
@@ -772,6 +776,22 @@ config ESP_TIMER_PROFILING
|
||||
used for timer storage, and should only be used for debugging/testing
|
||||
purposes.
|
||||
|
||||
config COMPATIBLE_PRE_V2_1_BOOTLOADERS
|
||||
bool "App compatible with bootloaders before IDF v2.1"
|
||||
default n
|
||||
help
|
||||
Bootloaders before IDF v2.1 did less initialisation of the
|
||||
system clock. This setting needs to be enabled to build an app
|
||||
which can be booted by these older bootloaders.
|
||||
|
||||
If this setting is enabled, the app can be booted by any bootloader
|
||||
from IDF v1.0 up to the current version.
|
||||
|
||||
If this setting is disabled, the app can only be booted by bootloaders
|
||||
from IDF v2.1 or newer.
|
||||
|
||||
Enabling this setting adds approximately 1KB to the app's IRAM usage.
|
||||
|
||||
endmenu # ESP32-Specific
|
||||
|
||||
menu Wi-Fi
|
||||
|
@@ -27,10 +27,10 @@
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "xtensa/core-macros.h"
|
||||
#include "bootloader_clock.h"
|
||||
|
||||
/* Number of cycles to wait from the 32k XTAL oscillator to consider it running.
|
||||
* Larger values increase startup delay. Smaller values may cause false positive
|
||||
@@ -54,6 +54,22 @@ void esp_clk_init(void)
|
||||
{
|
||||
rtc_config_t cfg = RTC_CONFIG_DEFAULT();
|
||||
rtc_init(cfg);
|
||||
|
||||
#ifdef CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS
|
||||
/* Check the bootloader set the XTAL frequency.
|
||||
|
||||
Bootloaders pre-v2.1 don't do this.
|
||||
*/
|
||||
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
|
||||
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
|
||||
ESP_EARLY_LOGW(TAG, "RTC domain not initialised by bootloader");
|
||||
bootloader_clock_configure();
|
||||
}
|
||||
#else
|
||||
/* If this assertion fails, either upgrade the bootloader or enable CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS */
|
||||
assert(rtc_clk_xtal_freq_get() != RTC_XTAL_FREQ_AUTO);
|
||||
#endif
|
||||
|
||||
rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M);
|
||||
|
||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
@@ -187,7 +203,7 @@ void esp_perip_clk_init(void)
|
||||
common_perip_clk = DPORT_WDG_CLK_EN |
|
||||
DPORT_I2S0_CLK_EN |
|
||||
#if CONFIG_CONSOLE_UART_NUM != 0
|
||||
DPORT_UART0_CLK_EN |
|
||||
DPORT_UART_CLK_EN |
|
||||
#endif
|
||||
#if CONFIG_CONSOLE_UART_NUM != 1
|
||||
DPORT_UART1_CLK_EN |
|
||||
@@ -203,10 +219,7 @@ void esp_perip_clk_init(void)
|
||||
DPORT_LEDC_CLK_EN |
|
||||
DPORT_UHCI1_CLK_EN |
|
||||
DPORT_TIMERGROUP1_CLK_EN |
|
||||
//80MHz SPIRAM uses SPI2 as well; it's initialized before this is called. Do not disable the clock for that if this is enabled.
|
||||
#if !CONFIG_SPIRAM_SPEED_80M
|
||||
DPORT_SPI_CLK_EN_2 |
|
||||
#endif
|
||||
DPORT_PWM0_CLK_EN |
|
||||
DPORT_I2C_EXT1_CLK_EN |
|
||||
DPORT_CAN_CLK_EN |
|
||||
@@ -228,6 +241,15 @@ void esp_perip_clk_init(void)
|
||||
DPORT_WIFI_CLK_EMAC_EN;
|
||||
}
|
||||
|
||||
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
//80MHz SPIRAM uses SPI2 as well; it's initialized before this is called. Because it is used in
|
||||
//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs'
|
||||
//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should
|
||||
//not modify that state, regardless of what we calculated earlier.
|
||||
common_perip_clk &= ~DPORT_SPI_CLK_EN_2;
|
||||
#endif
|
||||
|
||||
/* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock,
|
||||
* the current is not reduced when disable I2S clock.
|
||||
*/
|
||||
|
@@ -35,7 +35,7 @@
|
||||
#include "tcpip_adapter.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
const char* TAG = "event";
|
||||
static const char* TAG = "event";
|
||||
|
||||
#define WIFI_API_CALL_CHECK(info, api_call, ret) \
|
||||
do{\
|
||||
|
@@ -37,13 +37,13 @@ extern "C" {
|
||||
*/
|
||||
|
||||
//Keep the LEVELx values as they are here; they match up with (1<<level)
|
||||
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL1 (1<<1) ///< Accept a Level 1 interrupt vector (lowest priority)
|
||||
#define ESP_INTR_FLAG_LEVEL2 (1<<2) ///< Accept a Level 2 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL3 (1<<3) ///< Accept a Level 3 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL4 (1<<4) ///< Accept a Level 4 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL5 (1<<5) ///< Accept a Level 5 interrupt vector
|
||||
#define ESP_INTR_FLAG_LEVEL6 (1<<6) ///< Accept a Level 6 interrupt vector
|
||||
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector
|
||||
#define ESP_INTR_FLAG_NMI (1<<7) ///< Accept a Level 7 interrupt vector (highest priority)
|
||||
#define ESP_INTR_FLAG_SHARED (1<<8) ///< Interrupt can be shared between ISRs
|
||||
#define ESP_INTR_FLAG_EDGE (1<<9) ///< Edge-triggered interrupt
|
||||
#define ESP_INTR_FLAG_IRAM (1<<10) ///< ISR can be called if cache is disabled
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
|
||||
@@ -492,6 +493,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
Application code should never touch VSPI hardware in this case. We try to stop applications
|
||||
from doing this using the drivers by claiming the port for ourselves*/
|
||||
if (mode == PSRAM_CACHE_F80M_S80M) {
|
||||
periph_module_enable(PERIPH_VSPI_MODULE);
|
||||
bool r=spicommon_periph_claim(VSPI_HOST);
|
||||
if (!r) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
@@ -502,12 +504,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
assert(mode < PSRAM_CACHE_MAX && "we don't support any other mode for now.");
|
||||
s_psram_mode = mode;
|
||||
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
|
||||
periph_module_enable(PERIPH_SPI_MODULE);
|
||||
|
||||
WRITE_PERI_REG(SPI_EXT3_REG(0), 0x1);
|
||||
CLEAR_PERI_REG_MASK(SPI_USER_REG(PSRAM_SPI_1), SPI_USR_PREP_HOLD_M);
|
||||
@@ -519,6 +516,8 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
gpio_matrix_out(PSRAM_CS_IO, SPICS1_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(PSRAM_CLK_IO, VSPICLK_OUT_IDX, 0, 0);
|
||||
//use spi3 clock,but use spi1 data/cs wires
|
||||
//We get a solid 80MHz clock from SPI3 by setting it up, starting a transaction, waiting until it
|
||||
//is in progress, then cutting the clock (but not the reset!) to that peripheral.
|
||||
WRITE_PERI_REG(SPI_ADDR_REG(PSRAM_SPI_3), 32 << 24);
|
||||
WRITE_PERI_REG(SPI_CLOCK_REG(PSRAM_SPI_3), SPI_CLK_EQU_SYSCLK_M); //SET 80M AND CLEAR OTHERS
|
||||
SET_PERI_REG_MASK(SPI_CMD_REG(PSRAM_SPI_3), SPI_FLASH_READ_M);
|
||||
@@ -526,7 +525,7 @@ esp_err_t IRAM_ATTR psram_enable(psram_cache_mode_t mode, psram_vaddr_mode_t vad
|
||||
while (1) {
|
||||
spi_status = READ_PERI_REG(SPI_EXT2_REG(PSRAM_SPI_3));
|
||||
if (spi_status != 0 && spi_status != 1) {
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, BIT(PSRAM_CS_IO)); //DPORT_SPI_CLK_EN
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -43,6 +43,25 @@ typedef struct {
|
||||
struct dirent cur_dirent;
|
||||
} vfs_fat_dir_t;
|
||||
|
||||
/* Date and time storage formats in FAT */
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t mday : 5; /* Day of month, 1 - 31 */
|
||||
uint16_t mon : 4; /* Month, 1 - 12 */
|
||||
uint16_t year : 7; /* Year, counting from 1980. E.g. 37 for 2017 */
|
||||
};
|
||||
uint16_t as_int;
|
||||
} fat_date_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint16_t sec : 5; /* Seconds divided by 2. E.g. 21 for 42 seconds */
|
||||
uint16_t min : 6; /* Minutes, 0 - 59 */
|
||||
uint16_t hour : 5; /* Hour, 0 - 23 */
|
||||
};
|
||||
uint16_t as_int;
|
||||
} fat_time_t;
|
||||
|
||||
static const char* TAG = "vfs_fat";
|
||||
|
||||
static ssize_t vfs_fat_write(void* p, int fd, const void * data, size_t size);
|
||||
@@ -389,11 +408,29 @@ static int vfs_fat_fstat(void* ctx, int fd, struct stat * st)
|
||||
FIL* file = &fat_ctx->files[fd];
|
||||
st->st_size = f_size(file);
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
||||
st->st_mtime = 0;
|
||||
st->st_atime = 0;
|
||||
st->st_ctime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline mode_t get_stat_mode(bool is_dir)
|
||||
{
|
||||
return S_IRWXU | S_IRWXG | S_IRWXO |
|
||||
((is_dir) ? S_IFDIR : S_IFREG);
|
||||
}
|
||||
|
||||
static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
|
||||
{
|
||||
if (strcmp(path, "/") == 0) {
|
||||
/* FatFS f_stat function does not work for the drive root.
|
||||
* Just pretend that this is a directory.
|
||||
*/
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_mode = get_stat_mode(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
|
||||
_lock_acquire(&fat_ctx->lock);
|
||||
prepend_drive_to_path(fat_ctx, &path, NULL);
|
||||
@@ -405,23 +442,23 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
|
||||
errno = fresult_to_errno(res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(st, 0, sizeof(*st));
|
||||
st->st_size = info.fsize;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO |
|
||||
((info.fattrib & AM_DIR) ? S_IFDIR : S_IFREG);
|
||||
struct tm tm;
|
||||
uint16_t fdate = info.fdate;
|
||||
tm.tm_mday = fdate & 0x1f;
|
||||
fdate >>= 5;
|
||||
tm.tm_mon = (fdate & 0xf) - 1;
|
||||
fdate >>=4;
|
||||
tm.tm_year = fdate + 80;
|
||||
uint16_t ftime = info.ftime;
|
||||
tm.tm_sec = (ftime & 0x1f) * 2;
|
||||
ftime >>= 5;
|
||||
tm.tm_min = (ftime & 0x3f);
|
||||
ftime >>= 6;
|
||||
tm.tm_hour = (ftime & 0x1f);
|
||||
st->st_mode = get_stat_mode((info.fattrib & AM_DIR) != 0);
|
||||
fat_date_t fdate = { .as_int = info.fdate };
|
||||
fat_time_t ftime = { .as_int = info.ftime };
|
||||
struct tm tm = {
|
||||
.tm_mday = fdate.mday,
|
||||
.tm_mon = fdate.mon - 1, /* unlike tm_mday, tm_mon is zero-based */
|
||||
.tm_year = fdate.year + 80,
|
||||
.tm_sec = ftime.sec * 2,
|
||||
.tm_min = ftime.min,
|
||||
.tm_hour = ftime.hour
|
||||
};
|
||||
st->st_mtime = mktime(&tm);
|
||||
st->st_atime = 0;
|
||||
st->st_ctime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -128,6 +128,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
||||
goto fail;
|
||||
}
|
||||
free(workbuf);
|
||||
workbuf = NULL;
|
||||
ESP_LOGW(TAG, "mounting again");
|
||||
res = f_mount(fs, drv, 0);
|
||||
if (res != FR_OK) {
|
||||
@@ -139,7 +140,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
sdmmc_host_deinit();
|
||||
host_config->deinit();
|
||||
free(workbuf);
|
||||
if (fs) {
|
||||
f_mount(NULL, drv, 0);
|
||||
@@ -160,10 +161,11 @@ esp_err_t esp_vfs_fat_sdmmc_unmount()
|
||||
char drv[3] = {(char)('0' + s_pdrv), ':', 0};
|
||||
f_mount(0, drv, 0);
|
||||
// release SD driver
|
||||
esp_err_t (*host_deinit)() = s_card->host.deinit;
|
||||
ff_diskio_unregister(s_pdrv);
|
||||
free(s_card);
|
||||
s_card = NULL;
|
||||
sdmmc_host_deinit();
|
||||
(*host_deinit)();
|
||||
esp_err_t err = esp_vfs_fat_unregister_path(s_base_path);
|
||||
free(s_base_path);
|
||||
s_base_path = NULL;
|
||||
|
@@ -125,15 +125,15 @@ void test_fatfs_lseek(const char* filename)
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
void test_fatfs_stat(const char* filename)
|
||||
void test_fatfs_stat(const char* filename, const char* root_dir)
|
||||
{
|
||||
struct tm tm;
|
||||
tm.tm_year = 2016 - 1900;
|
||||
tm.tm_mon = 0;
|
||||
tm.tm_mday = 10;
|
||||
tm.tm_hour = 16;
|
||||
tm.tm_min = 30;
|
||||
tm.tm_sec = 0;
|
||||
tm.tm_year = 2017 - 1900;
|
||||
tm.tm_mon = 11;
|
||||
tm.tm_mday = 8;
|
||||
tm.tm_hour = 19;
|
||||
tm.tm_min = 51;
|
||||
tm.tm_sec = 10;
|
||||
time_t t = mktime(&tm);
|
||||
printf("Setting time: %s", asctime(&tm));
|
||||
struct timeval now = { .tv_sec = t };
|
||||
@@ -151,6 +151,11 @@ void test_fatfs_stat(const char* filename)
|
||||
|
||||
TEST_ASSERT(st.st_mode & S_IFREG);
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFDIR);
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
TEST_ASSERT_EQUAL(0, stat(root_dir, &st));
|
||||
TEST_ASSERT(st.st_mode & S_IFDIR);
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFREG);
|
||||
}
|
||||
|
||||
void test_fatfs_unlink(const char* filename)
|
||||
|
@@ -43,7 +43,7 @@ void test_fatfs_open_max_files(const char* filename_prefix, size_t files_count);
|
||||
|
||||
void test_fatfs_lseek(const char* filename);
|
||||
|
||||
void test_fatfs_stat(const char* filename);
|
||||
void test_fatfs_stat(const char* filename, const char* root_dir);
|
||||
|
||||
void test_fatfs_unlink(const char* filename);
|
||||
|
||||
|
@@ -105,7 +105,7 @@ TEST_CASE("(SD) can lseek", "[fatfs][sdcard][ignore]")
|
||||
TEST_CASE("(SD) stat returns correct values", "[fatfs][ignore]")
|
||||
{
|
||||
test_setup();
|
||||
test_fatfs_stat("/sdcard/stat.txt");
|
||||
test_fatfs_stat("/sdcard/stat.txt", "/sdcard");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@@ -100,7 +100,7 @@ TEST_CASE("(WL) can lseek", "[fatfs][wear_levelling]")
|
||||
TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
|
||||
{
|
||||
test_setup();
|
||||
test_fatfs_stat("/spiflash/stat.txt");
|
||||
test_fatfs_stat("/spiflash/stat.txt", "/spiflash");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
@@ -104,7 +104,6 @@ extern "C" {
|
||||
* used to create a synchronisation point between multiple tasks (a
|
||||
* 'rendezvous').
|
||||
*
|
||||
* \defgroup EventGroup
|
||||
*/
|
||||
|
||||
|
||||
@@ -116,7 +115,6 @@ extern "C" {
|
||||
* xEventGroupCreate() returns an EventGroupHandle_t variable that can then
|
||||
* be used as a parameter to other event group functions.
|
||||
*
|
||||
* \defgroup EventGroupHandle_t EventGroupHandle_t
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
typedef void * EventGroupHandle_t;
|
||||
@@ -126,17 +124,11 @@ typedef void * EventGroupHandle_t;
|
||||
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
|
||||
* 32 bits if set to 0.
|
||||
*
|
||||
* \defgroup EventBits_t EventBits_t
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
@@ -162,25 +154,24 @@ typedef TickType_t EventBits_t;
|
||||
* event group then NULL is returned. See http://www.freertos.org/a00111.html
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Declare a variable to hold the created event group.
|
||||
EventGroupHandle_t xCreatedEventGroup;
|
||||
|
||||
// Attempt to create the event group.
|
||||
xCreatedEventGroup = xEventGroupCreate();
|
||||
|
||||
// Was the event group created successfully?
|
||||
if( xCreatedEventGroup == NULL )
|
||||
{
|
||||
// The event group was not created because there was insufficient
|
||||
// FreeRTOS heap available.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The event group was created.
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupCreate xEventGroupCreate
|
||||
* @code{c}
|
||||
* // Declare a variable to hold the created event group.
|
||||
* EventGroupHandle_t xCreatedEventGroup;
|
||||
*
|
||||
* // Attempt to create the event group.
|
||||
* xCreatedEventGroup = xEventGroupCreate();
|
||||
*
|
||||
* // Was the event group created successfully?
|
||||
* if( xCreatedEventGroup == NULL )
|
||||
* {
|
||||
* // The event group was not created because there was insufficient
|
||||
* // FreeRTOS heap available.
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // The event group was created.
|
||||
* }
|
||||
* @endcode
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
@@ -188,11 +179,6 @@ typedef TickType_t EventBits_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
@@ -221,35 +207,26 @@ typedef TickType_t EventBits_t;
|
||||
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// StaticEventGroup_t is a publicly accessible structure that has the same
|
||||
// size and alignment requirements as the real event group structure. It is
|
||||
// provided as a mechanism for applications to know the size of the event
|
||||
// group (which is dependent on the architecture and configuration file
|
||||
// settings) without breaking the strict data hiding policy by exposing the
|
||||
// real event group internals. This StaticEventGroup_t variable is passed
|
||||
// into the xSemaphoreCreateEventGroupStatic() function and is used to store
|
||||
// the event group's data structures
|
||||
StaticEventGroup_t xEventGroupBuffer;
|
||||
|
||||
// Create the event group without dynamically allocating any memory.
|
||||
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
</pre>
|
||||
* @code{c}
|
||||
* // StaticEventGroup_t is a publicly accessible structure that has the same
|
||||
* // size and alignment requirements as the real event group structure. It is
|
||||
* // provided as a mechanism for applications to know the size of the event
|
||||
* // group (which is dependent on the architecture and configuration file
|
||||
* // settings) without breaking the strict data hiding policy by exposing the
|
||||
* // real event group internals. This StaticEventGroup_t variable is passed
|
||||
* // into the xSemaphoreCreateEventGroupStatic() function and is used to store
|
||||
* // the event group's data structures
|
||||
* StaticEventGroup_t xEventGroupBuffer;
|
||||
*
|
||||
* // Create the event group without dynamically allocating any memory.
|
||||
* xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
* @endcode
|
||||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
const TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* [Potentially] block to wait for one or more bits to be set within a
|
||||
* previously created event group.
|
||||
*
|
||||
@@ -292,54 +269,48 @@ typedef TickType_t EventBits_t;
|
||||
* pdTRUE.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
|
||||
// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
|
||||
// the event group. Clear the bits before exiting.
|
||||
uxBits = xEventGroupWaitBits(
|
||||
xEventGroup, // The event group being tested.
|
||||
BIT_0 | BIT_4, // The bits within the event group to wait for.
|
||||
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
|
||||
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because both bits were set.
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because just BIT_0 was set.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because just BIT_4 was set.
|
||||
}
|
||||
else
|
||||
{
|
||||
// xEventGroupWaitBits() returned because xTicksToWait ticks passed
|
||||
// without either BIT_0 or BIT_4 becoming set.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupWaitBits xEventGroupWaitBits
|
||||
* @code{c}
|
||||
* #define BIT_0 ( 1 << 0 )
|
||||
* #define BIT_4 ( 1 << 4 )
|
||||
*
|
||||
* void aFunction( EventGroupHandle_t xEventGroup )
|
||||
* {
|
||||
* EventBits_t uxBits;
|
||||
* const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
*
|
||||
* // Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
|
||||
* // the event group. Clear the bits before exiting.
|
||||
* uxBits = xEventGroupWaitBits(
|
||||
* xEventGroup, // The event group being tested.
|
||||
* BIT_0 | BIT_4, // The bits within the event group to wait for.
|
||||
* pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
|
||||
* pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
* xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
|
||||
*
|
||||
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
* {
|
||||
* // xEventGroupWaitBits() returned because both bits were set.
|
||||
* }
|
||||
* else if( ( uxBits & BIT_0 ) != 0 )
|
||||
* {
|
||||
* // xEventGroupWaitBits() returned because just BIT_0 was set.
|
||||
* }
|
||||
* else if( ( uxBits & BIT_4 ) != 0 )
|
||||
* {
|
||||
* // xEventGroupWaitBits() returned because just BIT_4 was set.
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // xEventGroupWaitBits() returned because xTicksToWait ticks passed
|
||||
* // without either BIT_0 or BIT_4 becoming set.
|
||||
* }
|
||||
* }
|
||||
* @endcode{c}
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
|
||||
</pre>
|
||||
*
|
||||
* Clear bits within an event group. This function cannot be called from an
|
||||
* interrupt.
|
||||
*
|
||||
@@ -352,51 +323,45 @@ EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits
|
||||
* @return The value of the event group before the specified bits were cleared.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
|
||||
// Clear bit 0 and bit 4 in xEventGroup.
|
||||
uxBits = xEventGroupClearBits(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 );// The bits being cleared.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
|
||||
// called. Both will now be clear (not set).
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// Bit 0 was set before xEventGroupClearBits() was called. It will
|
||||
// now be clear.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// Bit 4 was set before xEventGroupClearBits() was called. It will
|
||||
// now be clear.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither bit 0 nor bit 4 were set in the first place.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupClearBits xEventGroupClearBits
|
||||
* @code{c}
|
||||
* #define BIT_0 ( 1 << 0 )
|
||||
* #define BIT_4 ( 1 << 4 )
|
||||
*
|
||||
* void aFunction( EventGroupHandle_t xEventGroup )
|
||||
* {
|
||||
* EventBits_t uxBits;
|
||||
*
|
||||
* // Clear bit 0 and bit 4 in xEventGroup.
|
||||
* uxBits = xEventGroupClearBits(
|
||||
* xEventGroup, // The event group being updated.
|
||||
* BIT_0 | BIT_4 );// The bits being cleared.
|
||||
*
|
||||
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
* {
|
||||
* // Both bit 0 and bit 4 were set before xEventGroupClearBits() was
|
||||
* // called. Both will now be clear (not set).
|
||||
* }
|
||||
* else if( ( uxBits & BIT_0 ) != 0 )
|
||||
* {
|
||||
* // Bit 0 was set before xEventGroupClearBits() was called. It will
|
||||
* // now be clear.
|
||||
* }
|
||||
* else if( ( uxBits & BIT_4 ) != 0 )
|
||||
* {
|
||||
* // Bit 4 was set before xEventGroupClearBits() was called. It will
|
||||
* // now be clear.
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Neither bit 0 nor bit 4 were set in the first place.
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupClearBits() that can be called from an interrupt.
|
||||
*
|
||||
* Setting bits in an event group is not a deterministic operation because there
|
||||
@@ -420,28 +385,27 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit
|
||||
* if the timer service queue was full.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
// An event group which it is assumed has already been created by a call to
|
||||
// xEventGroupCreate().
|
||||
EventGroupHandle_t xEventGroup;
|
||||
|
||||
void anInterruptHandler( void )
|
||||
{
|
||||
// Clear bit 0 and bit 4 in xEventGroup.
|
||||
xResult = xEventGroupClearBitsFromISR(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 ); // The bits being set.
|
||||
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// The message was posted successfully.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
|
||||
* @code{c}
|
||||
* #define BIT_0 ( 1 << 0 )
|
||||
* #define BIT_4 ( 1 << 4 )
|
||||
*
|
||||
* // An event group which it is assumed has already been created by a call to
|
||||
* // xEventGroupCreate().
|
||||
* EventGroupHandle_t xEventGroup;
|
||||
*
|
||||
* void anInterruptHandler( void )
|
||||
* {
|
||||
* // Clear bit 0 and bit 4 in xEventGroup.
|
||||
* xResult = xEventGroupClearBitsFromISR(
|
||||
* xEventGroup, // The event group being updated.
|
||||
* BIT_0 | BIT_4 ); // The bits being set.
|
||||
*
|
||||
* if( xResult == pdPASS )
|
||||
* {
|
||||
* // The message was posted successfully.
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
@@ -451,11 +415,6 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||
</pre>
|
||||
*
|
||||
* Set bits within an event group.
|
||||
* This function cannot be called from an interrupt. xEventGroupSetBitsFromISR()
|
||||
* is a version that can be called from an interrupt.
|
||||
@@ -480,56 +439,50 @@ EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBit
|
||||
* event group value before the call to xEventGroupSetBits() returns.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
|
||||
// Set bit 0 and bit 4 in xEventGroup.
|
||||
uxBits = xEventGroupSetBits(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 );// The bits being set.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// Both bit 0 and bit 4 remained set when the function returned.
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// Bit 0 remained set when the function returned, but bit 4 was
|
||||
// cleared. It might be that bit 4 was cleared automatically as a
|
||||
// task that was waiting for bit 4 was removed from the Blocked
|
||||
// state.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// Bit 4 remained set when the function returned, but bit 0 was
|
||||
// cleared. It might be that bit 0 was cleared automatically as a
|
||||
// task that was waiting for bit 0 was removed from the Blocked
|
||||
// state.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither bit 0 nor bit 4 remained set. It might be that a task
|
||||
// was waiting for both of the bits to be set, and the bits were
|
||||
// cleared as the task left the Blocked state.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupSetBits xEventGroupSetBits
|
||||
* @code{c}
|
||||
* #define BIT_0 ( 1 << 0 )
|
||||
* #define BIT_4 ( 1 << 4 )
|
||||
*
|
||||
* void aFunction( EventGroupHandle_t xEventGroup )
|
||||
* {
|
||||
* EventBits_t uxBits;
|
||||
*
|
||||
* // Set bit 0 and bit 4 in xEventGroup.
|
||||
* uxBits = xEventGroupSetBits(
|
||||
* xEventGroup, // The event group being updated.
|
||||
* BIT_0 | BIT_4 );// The bits being set.
|
||||
*
|
||||
* if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
* {
|
||||
* // Both bit 0 and bit 4 remained set when the function returned.
|
||||
* }
|
||||
* else if( ( uxBits & BIT_0 ) != 0 )
|
||||
* {
|
||||
* // Bit 0 remained set when the function returned, but bit 4 was
|
||||
* // cleared. It might be that bit 4 was cleared automatically as a
|
||||
* // task that was waiting for bit 4 was removed from the Blocked
|
||||
* // state.
|
||||
* }
|
||||
* else if( ( uxBits & BIT_4 ) != 0 )
|
||||
* {
|
||||
* // Bit 4 remained set when the function returned, but bit 0 was
|
||||
* // cleared. It might be that bit 0 was cleared automatically as a
|
||||
* // task that was waiting for bit 0 was removed from the Blocked
|
||||
* // state.
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Neither bit 0 nor bit 4 remained set. It might be that a task
|
||||
* // was waiting for both of the bits to be set, and the bits were
|
||||
* // cleared as the task left the Blocked state.
|
||||
* }
|
||||
* }
|
||||
* @endcode{c}
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupSetBits() that can be called from an interrupt.
|
||||
*
|
||||
* Setting bits in an event group is not a deterministic operation because there
|
||||
@@ -561,39 +514,38 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_
|
||||
* if the timer service queue was full.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
// An event group which it is assumed has already been created by a call to
|
||||
// xEventGroupCreate().
|
||||
EventGroupHandle_t xEventGroup;
|
||||
|
||||
void anInterruptHandler( void )
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken, xResult;
|
||||
|
||||
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
|
||||
xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
// Set bit 0 and bit 4 in xEventGroup.
|
||||
xResult = xEventGroupSetBitsFromISR(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 // The bits being set.
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
// Was the message posted successfully?
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
|
||||
// switch should be requested. The macro used is port specific and
|
||||
// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
|
||||
// refer to the documentation page for the port being used.
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
|
||||
* @code{c}
|
||||
* #define BIT_0 ( 1 << 0 )
|
||||
* #define BIT_4 ( 1 << 4 )
|
||||
*
|
||||
* // An event group which it is assumed has already been created by a call to
|
||||
* // xEventGroupCreate().
|
||||
* EventGroupHandle_t xEventGroup;
|
||||
*
|
||||
* void anInterruptHandler( void )
|
||||
* {
|
||||
* BaseType_t xHigherPriorityTaskWoken, xResult;
|
||||
*
|
||||
* // xHigherPriorityTaskWoken must be initialised to pdFALSE.
|
||||
* xHigherPriorityTaskWoken = pdFALSE;
|
||||
*
|
||||
* // Set bit 0 and bit 4 in xEventGroup.
|
||||
* xResult = xEventGroupSetBitsFromISR(
|
||||
* xEventGroup, // The event group being updated.
|
||||
* BIT_0 | BIT_4 // The bits being set.
|
||||
* &xHigherPriorityTaskWoken );
|
||||
*
|
||||
* // Was the message posted successfully?
|
||||
* if( xResult == pdPASS )
|
||||
* {
|
||||
* // If xHigherPriorityTaskWoken is now set to pdTRUE then a context
|
||||
* // switch should be requested. The macro used is port specific and
|
||||
* // will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
|
||||
* // refer to the documentation page for the port being used.
|
||||
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
@@ -603,14 +555,6 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* Atomically set bits within an event group, then wait for a combination of
|
||||
* bits to be set within the same event group. This functionality is typically
|
||||
* used to synchronise multiple tasks, where each task has to wait for the other
|
||||
@@ -648,93 +592,87 @@ EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_
|
||||
* automatically cleared.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Bits used by the three tasks.
|
||||
#define TASK_0_BIT ( 1 << 0 )
|
||||
#define TASK_1_BIT ( 1 << 1 )
|
||||
#define TASK_2_BIT ( 1 << 2 )
|
||||
|
||||
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
|
||||
|
||||
// Use an event group to synchronise three tasks. It is assumed this event
|
||||
// group has already been created elsewhere.
|
||||
EventGroupHandle_t xEventBits;
|
||||
|
||||
void vTask0( void *pvParameters )
|
||||
{
|
||||
EventBits_t uxReturn;
|
||||
TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 0 in the event flag to note this task has reached the
|
||||
// sync point. The other two tasks will set the other two bits defined
|
||||
// by ALL_SYNC_BITS. All three tasks have reached the synchronisation
|
||||
// point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
|
||||
// for this to happen.
|
||||
uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
|
||||
|
||||
if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
|
||||
{
|
||||
// All three tasks reached the synchronisation point before the call
|
||||
// to xEventGroupSync() timed out.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vTask1( void *pvParameters )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 1 in the event flag to note this task has reached the
|
||||
// synchronisation point. The other two tasks will set the other two
|
||||
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
// indefinitely for this to happen.
|
||||
xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
|
||||
// xEventGroupSync() was called with an indefinite block time, so
|
||||
// this task will only reach here if the syncrhonisation was made by all
|
||||
// three tasks, so there is no need to test the return value.
|
||||
}
|
||||
}
|
||||
|
||||
void vTask2( void *pvParameters )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 2 in the event flag to note this task has reached the
|
||||
// synchronisation point. The other two tasks will set the other two
|
||||
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
// indefinitely for this to happen.
|
||||
xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
|
||||
// xEventGroupSync() was called with an indefinite block time, so
|
||||
// this task will only reach here if the syncrhonisation was made by all
|
||||
// three tasks, so there is no need to test the return value.
|
||||
}
|
||||
}
|
||||
|
||||
</pre>
|
||||
* \defgroup xEventGroupSync xEventGroupSync
|
||||
* @code{c}
|
||||
* // Bits used by the three tasks.
|
||||
* #define TASK_0_BIT ( 1 << 0 )
|
||||
* #define TASK_1_BIT ( 1 << 1 )
|
||||
* #define TASK_2_BIT ( 1 << 2 )
|
||||
*
|
||||
* #define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
|
||||
*
|
||||
* // Use an event group to synchronise three tasks. It is assumed this event
|
||||
* // group has already been created elsewhere.
|
||||
* EventGroupHandle_t xEventBits;
|
||||
*
|
||||
* void vTask0( void *pvParameters )
|
||||
* {
|
||||
* EventBits_t uxReturn;
|
||||
* TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
*
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Perform task functionality here.
|
||||
*
|
||||
* // Set bit 0 in the event flag to note this task has reached the
|
||||
* // sync point. The other two tasks will set the other two bits defined
|
||||
* // by ALL_SYNC_BITS. All three tasks have reached the synchronisation
|
||||
* // point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
|
||||
* // for this to happen.
|
||||
* uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
|
||||
*
|
||||
* if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
|
||||
* {
|
||||
* // All three tasks reached the synchronisation point before the call
|
||||
* // to xEventGroupSync() timed out.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* void vTask1( void *pvParameters )
|
||||
* {
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Perform task functionality here.
|
||||
*
|
||||
* // Set bit 1 in the event flag to note this task has reached the
|
||||
* // synchronisation point. The other two tasks will set the other two
|
||||
* // bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
* // synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
* // indefinitely for this to happen.
|
||||
* xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
*
|
||||
* // xEventGroupSync() was called with an indefinite block time, so
|
||||
* // this task will only reach here if the syncrhonisation was made by all
|
||||
* // three tasks, so there is no need to test the return value.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* void vTask2( void *pvParameters )
|
||||
* {
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Perform task functionality here.
|
||||
*
|
||||
* // Set bit 2 in the event flag to note this task has reached the
|
||||
* // synchronisation point. The other two tasks will set the other two
|
||||
* // bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
* // synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
* // indefinitely for this to happen.
|
||||
* xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
*
|
||||
* // xEventGroupSync() was called with an indefinite block time, so
|
||||
* // this task will only reach here if the syncrhonisation was made by all
|
||||
* // three tasks, so there is no need to test the return value.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* Returns the current value of the bits in an event group. This function
|
||||
* cannot be used from an interrupt.
|
||||
*
|
||||
@@ -742,33 +680,22 @@ EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t u
|
||||
*
|
||||
* @return The event group bits at the time xEventGroupGetBits() was called.
|
||||
*
|
||||
* \defgroup xEventGroupGetBits xEventGroupGetBits
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupGetBits() that can be called from an ISR.
|
||||
*
|
||||
* @param xEventGroup The event group being queried.
|
||||
*
|
||||
* @return The event group bits at the time xEventGroupGetBitsFromISR() was called.
|
||||
*
|
||||
* \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
void xEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* Delete an event group that was previously created by a call to
|
||||
* xEventGroupCreate(). Tasks that are blocked on the event group will be
|
||||
@@ -778,6 +705,8 @@ EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
|
||||
*/
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
|
||||
/** @cond */
|
||||
|
||||
/* For internal use only. */
|
||||
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet );
|
||||
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear );
|
||||
@@ -786,6 +715,8 @@ void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToCl
|
||||
UBaseType_t uxEventGroupGetNumber( void* xEventGroup );
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,50 +9,58 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Header definitions for a FreeRTOS ringbuffer object
|
||||
|
||||
A ringbuffer instantiated by these functions essentially acts like a FreeRTOS queue, with the
|
||||
difference that it's strictly FIFO and with the main advantage that you can put in randomly-sized
|
||||
items. The capacity, accordingly, isn't measured in the amount of items, but the amount of memory
|
||||
that is used for storing the items. Dependent on the size of the items, more or less of them will
|
||||
fit in the ring buffer.
|
||||
|
||||
This ringbuffer tries to be efficient with memory: when inserting an item, the item data will
|
||||
be copied to the ringbuffer memory. When retrieving an item, however, a reference to ringbuffer
|
||||
memory will be returned. The returned memory is guaranteed to be 32-bit aligned and contiguous.
|
||||
The application can use this memory, but as long as it does, ringbuffer writes that would write
|
||||
to this bit of memory will block.
|
||||
|
||||
The requirement for items to be contiguous is slightly problematic when the only way to place
|
||||
the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can
|
||||
be solved (or not) in a few ways:
|
||||
- type = RINGBUF_TYPE_ALLOWSPLIT: The insertion code will split the item in two items; one which fits
|
||||
in the space left at the end of the ringbuffer, one that contains the remaining data which is placed
|
||||
in the beginning. Two xRingbufferReceive calls will be needed to retrieve the data.
|
||||
- type = RINGBUF_TYPE_NOSPLIT: The insertion code will leave the room at the end of the ringbuffer
|
||||
unused and instead will put the entire item at the start of the ringbuffer, as soon as there is
|
||||
enough free space.
|
||||
- type = RINGBUF_TYPE_BYTEBUF: This is your conventional byte-based ringbuffer. It does have no
|
||||
overhead, but it has no item contiguousness either: a read will just give you the entire written
|
||||
buffer space, or the space up to the end of the buffer, and writes can be broken up in any way
|
||||
possible. Note that this type cannot do a 2nd read before returning the memory of the 1st.
|
||||
|
||||
The maximum size of an item will be affected by this decision. When split items are allowed, it's
|
||||
acceptable to push items of (buffer_size)-16 bytes into the buffer. When it's not allowed, the
|
||||
maximum size is (buffer_size/2)-8 bytes. The bytebuf can fill the entire buffer with data, it has
|
||||
no overhead.
|
||||
*/
|
||||
|
||||
#include <freertos/queue.h>
|
||||
|
||||
//An opaque handle for a ringbuff object.
|
||||
typedef void * RingbufHandle_t;
|
||||
|
||||
//The various types of buffer
|
||||
/**
|
||||
* @brief The various types of buffer
|
||||
*
|
||||
* A ringbuffer instantiated by these functions essentially acts like a
|
||||
* FreeRTOS queue, with the difference that it's strictly FIFO and with
|
||||
* the main advantage that you can put in randomly-sized items. The capacity,
|
||||
* accordingly, isn't measured in the amount of items, but the amount of
|
||||
* memory that is used for storing the items. Dependent on the size of
|
||||
* the items, more or less of them will fit in the ring buffer.
|
||||
*
|
||||
* This ringbuffer tries to be efficient with memory: when inserting an item,
|
||||
* the item data will be copied to the ringbuffer memory. When retrieving
|
||||
* an item, however, a reference to ringbuffer memory will be returned.
|
||||
* The returned memory is guaranteed to be 32-bit aligned and contiguous.
|
||||
* The application can use this memory, but as long as it does, ringbuffer
|
||||
* writes that would write to this bit of memory will block.
|
||||
*
|
||||
* The requirement for items to be contiguous is slightly problematic when
|
||||
* the only way to place the next item would involve a wraparound from the end
|
||||
* to the beginning of the ringbuffer. This can be solved (or not) in a few ways,
|
||||
* see descriptions of possible ringbuf_type_t types below.
|
||||
*
|
||||
* The maximum size of an item will be affected by ringbuffer type.
|
||||
* When split items are allowed, it is acceptable to push items of
|
||||
* (buffer_size)-16 bytes into the buffer.
|
||||
* When it's not allowed, the maximum size is (buffer_size/2)-8 bytes.
|
||||
* The bytebuf can fill the entire buffer with data, it has no overhead.
|
||||
*/
|
||||
typedef enum {
|
||||
/** The insertion code will leave the room at the end of the ringbuffer
|
||||
* unused and instead will put the entire item at the start of the ringbuffer,
|
||||
* as soon as there is enough free space.
|
||||
*/
|
||||
RINGBUF_TYPE_NOSPLIT = 0,
|
||||
/** The insertion code will split the item in two items; one which fits
|
||||
* in the space left at the end of the ringbuffer, one that contains
|
||||
* the remaining data which is placed in the beginning.
|
||||
* Two xRingbufferReceive calls will be needed to retrieve the data.
|
||||
*/
|
||||
RINGBUF_TYPE_ALLOWSPLIT,
|
||||
/** This is your conventional byte-based ringbuffer. It does have no
|
||||
* overhead, but it has no item contiguousness either: a read will just
|
||||
* give you the entire written buffer space, or the space up to the end
|
||||
* of the buffer, and writes can be broken up in any way possible.
|
||||
* Note that this type cannot do a 2nd read before returning the memory
|
||||
* of the 1st.
|
||||
*/
|
||||
RINGBUF_TYPE_BYTEBUF
|
||||
} ringbuf_type_t;
|
||||
|
||||
@@ -60,22 +68,32 @@ typedef enum {
|
||||
/**
|
||||
* @brief Create a ring buffer
|
||||
*
|
||||
* @param buf_length : Length of circular buffer, in bytes. Each entry will take up its own length, plus a header
|
||||
* that at the moment is equal to sizeof(size_t).
|
||||
* @param allow_split_items : pdTRUE if it is acceptable that item data is inserted as two
|
||||
* items instead of one.
|
||||
* @param buf_length Length of circular buffer, in bytes. Each entry will
|
||||
* take up its own length, plus a header that at the moment
|
||||
* is equal to sizeof(size_t).
|
||||
* @param type Type of ring buffer, see ringbuf_type_t.
|
||||
*
|
||||
* @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
|
||||
*/
|
||||
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Create a ring buffer of type RINGBUF_TYPE_NOSPLIT for a fixed item_size
|
||||
*
|
||||
* This API is similar to xRingbufferCreate(), but it will internally allocate
|
||||
* additional space for the headers.
|
||||
*
|
||||
* @param item_size Size of each item to be put into the ring buffer
|
||||
* @param num_item Maximum number of items the buffer needs to hold simultaneously
|
||||
*
|
||||
* @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
|
||||
*/
|
||||
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item);
|
||||
|
||||
/**
|
||||
* @brief Delete a ring buffer
|
||||
*
|
||||
* @param ringbuf - Ring buffer to delete
|
||||
*
|
||||
* @return void
|
||||
* @param ringbuf Ring buffer to delete
|
||||
*/
|
||||
void vRingbufferDelete(RingbufHandle_t ringbuf);
|
||||
|
||||
@@ -83,23 +101,57 @@ void vRingbufferDelete(RingbufHandle_t ringbuf);
|
||||
/**
|
||||
* @brief Get maximum size of an item that can be placed in the ring buffer
|
||||
*
|
||||
* @param ringbuf - Ring buffer to query
|
||||
* @param ringbuf Ring buffer to query
|
||||
*
|
||||
* @return Maximum size, in bytes, of an item that can be placed in a ring buffer.
|
||||
*/
|
||||
size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf);
|
||||
|
||||
/**
|
||||
* @brief Get current free size available in the buffer
|
||||
*
|
||||
* This gives the real time free space available in the ring buffer. So basically,
|
||||
* this will be the maximum size of the entry that can be sent into the buffer.
|
||||
*
|
||||
* @note This API is not thread safe. So, if multiple threads are accessing the same
|
||||
* ring buffer, it is the application's responsibility to ensure atomic access to this
|
||||
* API and the subsequent Send
|
||||
*
|
||||
* @param ringbuf - Ring buffer to query
|
||||
*
|
||||
* @return Current free size, in bytes, available for an entry
|
||||
*/
|
||||
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf);
|
||||
|
||||
/**
|
||||
* @brief Check if the next item is wrapped
|
||||
*
|
||||
* This API tells if the next item that is available for a Receive is wrapped
|
||||
* or not. This is valid only if the ring buffer type is RINGBUF_TYPE_ALLOWSPLIT
|
||||
*
|
||||
* @note This API is not thread safe. So, if multiple threads are accessing the same
|
||||
* ring buffer, it is the application's responsibility to ensure atomic access to this
|
||||
* API and the subsequent Receive
|
||||
*
|
||||
* @param ringbuf - Ring buffer to query
|
||||
*
|
||||
* @return true if the next item is wrapped around
|
||||
* @return false if the next item is not wrapped
|
||||
*/
|
||||
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf);
|
||||
|
||||
/**
|
||||
* @brief Insert an item into the ring buffer
|
||||
*
|
||||
* @param ringbuf - Ring buffer to insert the item into
|
||||
* @param data - Pointer to data to insert. NULL is allowed if data_size is 0.
|
||||
* @param data_size - Size of data to insert. A value of 0 is allowed.
|
||||
* @param xTicksToWait - Ticks to wait for room in the ringbuffer.
|
||||
* @param ringbuf Ring buffer to insert the item into
|
||||
* @param data Pointer to data to insert. NULL is allowed if data_size is 0.
|
||||
* @param data_size Size of data to insert. A value of 0 is allowed.
|
||||
* @param ticks_to_wait Ticks to wait for room in the ringbuffer.
|
||||
*
|
||||
* @return pdTRUE if succeeded, pdFALSE on time-out or when the buffer is larger
|
||||
* than indicated by xRingbufferGetMaxItemSize(ringbuf).
|
||||
* @return
|
||||
* - pdTRUE if succeeded
|
||||
* - pdFALSE on time-out or when the buffer is larger than indicated
|
||||
* by xRingbufferGetMaxItemSize(ringbuf).
|
||||
*/
|
||||
BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t data_size, TickType_t ticks_to_wait);
|
||||
|
||||
@@ -107,11 +159,11 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t data_size
|
||||
/**
|
||||
* @brief Insert an item into the ring buffer from an ISR
|
||||
*
|
||||
* @param ringbuf - Ring buffer to insert the item into
|
||||
* @param data - Pointer to data to insert. NULL is allowed if data_size is 0.
|
||||
* @param data_size - Size of data to insert. A value of 0 is allowed.
|
||||
* @param higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
|
||||
* priority task.
|
||||
* @param ringbuf Ring buffer to insert the item into
|
||||
* @param data Pointer to data to insert. NULL is allowed if data_size is 0.
|
||||
* @param data_size Size of data to insert. A value of 0 is allowed.
|
||||
* @param[out] higher_prio_task_awoken Value pointed to will be set to pdTRUE
|
||||
* if the push woke up a higher priority task.
|
||||
*
|
||||
* @return pdTRUE if succeeded, pdFALSE when the ring buffer does not have space.
|
||||
*/
|
||||
@@ -120,14 +172,18 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da
|
||||
/**
|
||||
* @brief Retrieve an item from the ring buffer
|
||||
*
|
||||
* @note A call to vRingbufferReturnItem() is required after this to free up the data received.
|
||||
* @note A call to vRingbufferReturnItem() is required after this to free up
|
||||
* the data received.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
* @param xTicksToWait - Ticks to wait for items in the ringbuffer.
|
||||
* @param ringbuf Ring buffer to retrieve the item from
|
||||
* @param[out] item_size Pointer to a variable to which the size of the
|
||||
* retrieved item will be written.
|
||||
* @param ticks_to_wait Ticks to wait for items in the ringbuffer.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL on timeout, *item_size is untouched in that case.
|
||||
* @return
|
||||
* - pointer to the retrieved item on success; *item_size filled with
|
||||
* the length of the item.
|
||||
* - NULL on timeout, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait);
|
||||
|
||||
@@ -135,44 +191,58 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
|
||||
/**
|
||||
* @brief Retrieve an item from the ring buffer from an ISR
|
||||
*
|
||||
* @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received
|
||||
* @note A call to vRingbufferReturnItemFromISR() is required after this to
|
||||
* free up the data received
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
* @param ringbuf Ring buffer to retrieve the item from
|
||||
* @param[out] item_size Pointer to a variable to which the size of the
|
||||
* retrieved item will be written.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL when the ringbuffer is empty, *item_size is untouched in that case.
|
||||
* @return
|
||||
* - Pointer to the retrieved item on success; *item_size filled with
|
||||
* the length of the item.
|
||||
* - NULL when the ringbuffer is empty, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
|
||||
* to return
|
||||
|
||||
* @note A call to vRingbufferReturnItem() is required after this to free up the data received.
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer,
|
||||
* specifying the maximum amount of bytes to return
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
* @param xTicksToWait - Ticks to wait for items in the ringbuffer.
|
||||
* @note A call to vRingbufferReturnItem() is required after this to free up
|
||||
* the data received.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL on timeout, *item_size is untouched in that case.
|
||||
* @param ringbuf Ring buffer to retrieve the item from
|
||||
* @param[out] item_size Pointer to a variable to which the size
|
||||
* of the retrieved item will be written.
|
||||
* @param ticks_to_wait Ticks to wait for items in the ringbuffer.
|
||||
* @param wanted_size Maximum number of bytes to return.
|
||||
*
|
||||
* @return
|
||||
* - Pointer to the retrieved item on success; *item_size filled with
|
||||
* the length of the item.
|
||||
* - NULL on timeout, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
|
||||
* to return. Call this from an ISR.
|
||||
* @brief Retrieve bytes from a ByteBuf type of ring buffer,
|
||||
* specifying the maximum amount of bytes to return. Call this from an ISR.
|
||||
*
|
||||
* @note A call to vRingbufferReturnItemFromISR() is required after this to free up the data received
|
||||
* @note A call to vRingbufferReturnItemFromISR() is required after this
|
||||
* to free up the data received.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to retrieve the item from
|
||||
* @param item_size - Pointer to a variable to which the size of the retrieved item will be written.
|
||||
* @param ringbuf Ring buffer to retrieve the item from
|
||||
* @param[out] item_size Pointer to a variable to which the size of the
|
||||
* retrieved item will be written.
|
||||
* @param wanted_size Maximum number of bytes to return.
|
||||
*
|
||||
* @return Pointer to the retrieved item on success; *item_size filled with the length of the
|
||||
* item. NULL when the ringbuffer is empty, *item_size is untouched in that case.
|
||||
* @return
|
||||
* - Pointer to the retrieved item on success; *item_size filled with
|
||||
* the length of the item.
|
||||
* - NULL when the ringbuffer is empty, *item_size is untouched in that case.
|
||||
*/
|
||||
void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size);
|
||||
|
||||
@@ -181,10 +251,8 @@ void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size,
|
||||
/**
|
||||
* @brief Return a previously-retrieved item to the ringbuffer
|
||||
*
|
||||
* @param ringbuf - Ring buffer the item was retrieved from
|
||||
* @param item - Item that was received earlier
|
||||
*
|
||||
* @return void
|
||||
* @param ringbuf Ring buffer the item was retrieved from
|
||||
* @param item Item that was received earlier
|
||||
*/
|
||||
void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item);
|
||||
|
||||
@@ -193,34 +261,37 @@ void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item);
|
||||
/**
|
||||
* @brief Return a previously-retrieved item to the ringbuffer from an ISR
|
||||
*
|
||||
* @param ringbuf - Ring buffer the item was retrieved from
|
||||
* @param item - Item that was received earlier
|
||||
* @param higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
|
||||
* priority task.
|
||||
*
|
||||
* @return void
|
||||
* @param ringbuf Ring buffer the item was retrieved from
|
||||
* @param item Item that was received earlier
|
||||
* @param[out] higher_prio_task_awoken Value pointed to will be set to pdTRUE
|
||||
* if the push woke up a higher priority task.
|
||||
*/
|
||||
void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_t *higher_prio_task_awoken);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
|
||||
* more space has become available in the ringbuffer.
|
||||
* @brief Add the ringbuffer to a queue set.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to add to the queue set
|
||||
* @param xQueueSet - Queue set to add the ringbuffer to
|
||||
* This specifically adds the semaphore that indicates more space
|
||||
* has become available in the ringbuffer.
|
||||
*
|
||||
* @return pdTRUE on success, pdFALSE otherwise
|
||||
* @param ringbuf Ring buffer to add to the queue set
|
||||
* @param xQueueSet Queue set to add the ringbuffer to
|
||||
*
|
||||
* @return
|
||||
* - pdTRUE on success, pdFALSE otherwise
|
||||
*/
|
||||
BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
|
||||
* something has been written into the ringbuffer.
|
||||
* @brief Add the ringbuffer to a queue set.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to add to the queue set
|
||||
* @param xQueueSet - Queue set to add the ringbuffer to
|
||||
* This specifically adds the semaphore that indicates something has been
|
||||
* written into the ringbuffer.
|
||||
*
|
||||
* @param ringbuf Ring buffer to add to the queue set
|
||||
* @param xQueueSet Queue set to add the ringbuffer to
|
||||
*
|
||||
* @return pdTRUE on success, pdFALSE otherwise
|
||||
*/
|
||||
@@ -228,11 +299,13 @@ BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
|
||||
* more space has become available in the ringbuffer.
|
||||
* @brief Remove the ringbuffer from a queue set.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to remove from the queue set
|
||||
* @param xQueueSet - Queue set to remove the ringbuffer from
|
||||
* This specifically removes the semaphore that indicates more space
|
||||
* has become available in the ringbuffer.
|
||||
*
|
||||
* @param ringbuf Ring buffer to remove from the queue set
|
||||
* @param xQueueSet Queue set to remove the ringbuffer from
|
||||
*
|
||||
* @return pdTRUE on success, pdFALSE otherwise
|
||||
*/
|
||||
@@ -240,11 +313,13 @@ BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t ringbuf, QueueSetHa
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
|
||||
* something has been written to the ringbuffer.
|
||||
* @brief Remove the ringbuffer from a queue set.
|
||||
*
|
||||
* @param ringbuf - Ring buffer to remove from the queue set
|
||||
* @param xQueueSet - Queue set to remove the ringbuffer from
|
||||
* This specifically removes the semaphore that indicates something
|
||||
* has been written to the ringbuffer.
|
||||
*
|
||||
* @param ringbuf Ring buffer to remove from the queue set
|
||||
* @param xQueueSet Queue set to remove the ringbuffer from
|
||||
*
|
||||
* @return pdTRUE on success, pdFALSE otherwise
|
||||
*/
|
||||
@@ -254,9 +329,7 @@ BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t ringbuf, QueueSetH
|
||||
/**
|
||||
* @brief Debugging function to print the internal pointers in the ring buffer
|
||||
*
|
||||
* @param ringbuf - Ring buffer to show
|
||||
*
|
||||
* @return void
|
||||
* @param ringbuf Ring buffer to show
|
||||
*/
|
||||
void xRingbufferPrintInfo(RingbufHandle_t ringbuf);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -117,24 +117,18 @@ or interrupt version of the queue send function should be used. */
|
||||
*/
|
||||
typedef void * TimerHandle_t;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Defines the prototype to which timer callback functions must conform.
|
||||
*/
|
||||
typedef void (*TimerCallbackFunction_t)( TimerHandle_t xTimer );
|
||||
|
||||
/*
|
||||
/**
|
||||
* Defines the prototype to which functions used with the
|
||||
* xTimerPendFunctionCallFromISR() function must conform.
|
||||
*/
|
||||
typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
|
||||
/**
|
||||
* TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
||||
* TickType_t xTimerPeriodInTicks,
|
||||
* UBaseType_t uxAutoReload,
|
||||
* void * pvTimerID,
|
||||
* TimerCallbackFunction_t pxCallbackFunction );
|
||||
*
|
||||
* Creates a new software timer instance, and returns a handle by which the
|
||||
* created software timer can be referenced.
|
||||
*
|
||||
@@ -184,7 +178,7 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
* structures, or the timer period was set to 0) then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* #define NUM_TIMERS 5
|
||||
*
|
||||
* // An array to hold handles to the created timers.
|
||||
@@ -263,7 +257,7 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
* // Should not reach here.
|
||||
* for( ;; );
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
||||
@@ -274,13 +268,6 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TimerHandle_t xTimerCreateStatic(const char * const pcTimerName,
|
||||
* TickType_t xTimerPeriodInTicks,
|
||||
* UBaseType_t uxAutoReload,
|
||||
* void * pvTimerID,
|
||||
* TimerCallbackFunction_t pxCallbackFunction,
|
||||
* StaticTimer_t *pxTimerBuffer );
|
||||
*
|
||||
* Creates a new software timer instance, and returns a handle by which the
|
||||
* created software timer can be referenced.
|
||||
*
|
||||
@@ -332,7 +319,7 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
* returned. If pxTimerBuffer was NULL then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
*
|
||||
* // The buffer used to hold the software timer's data structure.
|
||||
* static StaticTimer_t xTimerBuffer;
|
||||
@@ -393,7 +380,7 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
* // Should not reach here.
|
||||
* for( ;; );
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
|
||||
@@ -405,8 +392,6 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
/**
|
||||
* void *pvTimerGetTimerID( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the ID assigned to the timer.
|
||||
*
|
||||
* IDs are assigned to timers using the pvTimerID parameter of the call to
|
||||
@@ -427,8 +412,6 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||
void *pvTimerGetTimerID( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
|
||||
*
|
||||
* Sets the ID assigned to the timer.
|
||||
*
|
||||
* IDs are assigned to timers using the pvTimerID parameter of the call to
|
||||
@@ -448,12 +431,12 @@ void *pvTimerGetTimerID( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer );
|
||||
*
|
||||
* Queries a timer to see if it is active or dormant.
|
||||
*
|
||||
* A timer will be dormant if:
|
||||
*
|
||||
* 1) It has been created but not started, or
|
||||
*
|
||||
* 2) It is an expired one-shot timer that has not been restarted.
|
||||
*
|
||||
* Timers are created in the dormant state. The xTimerStart(), xTimerReset(),
|
||||
@@ -467,7 +450,7 @@ void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION
|
||||
* pdFALSE will be returned if the timer is active.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This function assumes xTimer has already been created.
|
||||
* void vAFunction( TimerHandle_t xTimer )
|
||||
* {
|
||||
@@ -480,13 +463,11 @@ void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) PRIVILEGED_FUNCTION
|
||||
* // xTimer is not active, do something else.
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
|
||||
*
|
||||
* xTimerGetTimerDaemonTaskHandle() is only available if
|
||||
* INCLUDE_xTimerGetTimerDaemonTaskHandle is set to 1 in FreeRTOSConfig.h.
|
||||
*
|
||||
@@ -496,8 +477,6 @@ BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
|
||||
|
||||
/**
|
||||
* TickType_t xTimerGetPeriod( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the period of a timer.
|
||||
*
|
||||
* @param xTimer The handle of the timer being queried.
|
||||
@@ -507,8 +486,6 @@ TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
|
||||
TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the time in ticks at which the timer will expire. If this is less
|
||||
* than the current tick count then the expiry time has overflowed from the
|
||||
* current time.
|
||||
@@ -522,8 +499,6 @@ TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||
*
|
||||
* Timer functionality is provided by a timer service/daemon task. Many of the
|
||||
* public FreeRTOS timer API functions send commands to the timer service task
|
||||
* through a queue called the timer command queue. The timer command queue is
|
||||
@@ -574,8 +549,6 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
#define xTimerStart( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||
*
|
||||
* Timer functionality is provided by a timer service/daemon task. Many of the
|
||||
* public FreeRTOS timer API functions send commands to the timer service task
|
||||
* through a queue called the timer command queue. The timer command queue is
|
||||
@@ -616,10 +589,6 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
#define xTimerStop( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
|
||||
* TickType_t xNewPeriod,
|
||||
* TickType_t xTicksToWait );
|
||||
*
|
||||
* Timer functionality is provided by a timer service/daemon task. Many of the
|
||||
* public FreeRTOS timer API functions send commands to the timer service task
|
||||
* through a queue called the timer command queue. The timer command queue is
|
||||
@@ -661,7 +630,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* configTIMER_TASK_PRIORITY configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This function assumes xTimer has already been created. If the timer
|
||||
* // referenced by xTimer is already active when it is called, then the timer
|
||||
* // is deleted. If the timer referenced by xTimer is not active when it is
|
||||
@@ -691,13 +660,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerChangePeriod( xTimer, xNewPeriod, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD, ( xNewPeriod ), NULL, ( xTicksToWait ) )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||
*
|
||||
* Timer functionality is provided by a timer service/daemon task. Many of the
|
||||
* public FreeRTOS timer API functions send commands to the timer service task
|
||||
* through a queue called the timer command queue. The timer command queue is
|
||||
@@ -734,8 +701,6 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
#define xTimerDelete( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_DELETE, 0U, NULL, ( xTicksToWait ) )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );
|
||||
*
|
||||
* Timer functionality is provided by a timer service/daemon task. Many of the
|
||||
* public FreeRTOS timer API functions send commands to the timer service task
|
||||
* through a queue called the timer command queue. The timer command queue is
|
||||
@@ -781,7 +746,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // When a key is pressed, an LCD back-light is switched on. If 5 seconds pass
|
||||
* // without a key being pressed, then the LCD back-light is switched off. In
|
||||
* // this case, the timer is a one-shot timer.
|
||||
@@ -853,14 +818,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* // Should not reach here.
|
||||
* for( ;; );
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerReset( xTimer, xTicksToWait ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerStartFromISR( TimerHandle_t xTimer,
|
||||
* BaseType_t *pxHigherPriorityTaskWoken );
|
||||
*
|
||||
* A version of xTimerStart() that can be called from an interrupt service
|
||||
* routine.
|
||||
*
|
||||
@@ -888,7 +850,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This scenario assumes xBacklightTimer has already been created. When a
|
||||
* // key is pressed, an LCD back-light is switched on. If 5 seconds pass
|
||||
* // without a key being pressed, then the LCD back-light is switched off. In
|
||||
@@ -939,14 +901,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* // depends on the FreeRTOS port being used).
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerStartFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerStopFromISR( TimerHandle_t xTimer,
|
||||
* BaseType_t *pxHigherPriorityTaskWoken );
|
||||
*
|
||||
* A version of xTimerStop() that can be called from an interrupt service
|
||||
* routine.
|
||||
*
|
||||
@@ -972,7 +931,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* priority is set by the configTIMER_TASK_PRIORITY configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This scenario assumes xTimer has already been created and started. When
|
||||
* // an interrupt occurs, the timer should be simply stopped.
|
||||
*
|
||||
@@ -1002,15 +961,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* // depends on the FreeRTOS port being used).
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerStopFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP_FROM_ISR, 0, ( pxHigherPriorityTaskWoken ), 0U )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer,
|
||||
* TickType_t xNewPeriod,
|
||||
* BaseType_t *pxHigherPriorityTaskWoken );
|
||||
*
|
||||
* A version of xTimerChangePeriod() that can be called from an interrupt
|
||||
* service routine.
|
||||
*
|
||||
@@ -1045,7 +1000,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* priority is set by the configTIMER_TASK_PRIORITY configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This scenario assumes xTimer has already been created and started. When
|
||||
* // an interrupt occurs, the period of xTimer should be changed to 500ms.
|
||||
*
|
||||
@@ -1075,14 +1030,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* // depends on the FreeRTOS port being used).
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD_FROM_ISR, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerResetFromISR( TimerHandle_t xTimer,
|
||||
* BaseType_t *pxHigherPriorityTaskWoken );
|
||||
*
|
||||
* A version of xTimerReset() that can be called from an interrupt service
|
||||
* routine.
|
||||
*
|
||||
@@ -1110,7 +1062,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* task priority is set by the configTIMER_TASK_PRIORITY configuration constant.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
* // This scenario assumes xBacklightTimer has already been created. When a
|
||||
* // key is pressed, an LCD back-light is switched on. If 5 seconds pass
|
||||
* // without a key being pressed, then the LCD back-light is switched off. In
|
||||
@@ -1161,18 +1113,12 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* // depends on the FreeRTOS port being used).
|
||||
* }
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
#define xTimerResetFromISR( xTimer, pxHigherPriorityTaskWoken ) xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET_FROM_ISR, ( xTaskGetTickCountFromISR() ), ( pxHigherPriorityTaskWoken ), 0U )
|
||||
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend,
|
||||
* void *pvParameter1,
|
||||
* uint32_t ulParameter2,
|
||||
* BaseType_t *pxHigherPriorityTaskWoken );
|
||||
*
|
||||
*
|
||||
* Used from application interrupt service routines to defer the execution of a
|
||||
* function to the RTOS daemon task (the timer service task, hence this function
|
||||
* is implemented in timers.c and is prefixed with 'Timer').
|
||||
@@ -1214,7 +1160,7 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* timer daemon task, otherwise pdFALSE is returned.
|
||||
*
|
||||
* Example usage:
|
||||
* @verbatim
|
||||
* @code{c}
|
||||
*
|
||||
* // The callback function that will execute in the context of the daemon task.
|
||||
* // Note callback functions must all use this same prototype.
|
||||
@@ -1252,17 +1198,11 @@ TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
|
||||
* portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
*
|
||||
* }
|
||||
* @endverbatim
|
||||
* @endcode
|
||||
*/
|
||||
BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
|
||||
/**
|
||||
* BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend,
|
||||
* void *pvParameter1,
|
||||
* uint32_t ulParameter2,
|
||||
* TickType_t xTicksToWait );
|
||||
*
|
||||
*
|
||||
* Used to defer the execution of a function to the RTOS daemon task (the timer
|
||||
* service task, hence this function is implemented in timers.c and is prefixed
|
||||
* with 'Timer').
|
||||
@@ -1291,8 +1231,6 @@ BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void
|
||||
BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait );
|
||||
|
||||
/**
|
||||
* const char * const pcTimerGetTimerName( TimerHandle_t xTimer );
|
||||
*
|
||||
* Returns the name that was assigned to a timer when the timer was created.
|
||||
*
|
||||
* @param xTimer The handle of the timer being queried.
|
||||
@@ -1301,6 +1239,7 @@ BaseType_t xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvPar
|
||||
*/
|
||||
const char * pcTimerGetTimerName( TimerHandle_t xTimer ); /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
|
||||
/** @cond */
|
||||
/*
|
||||
* Functions beyond this part are not part of the public API and are intended
|
||||
* for use by the kernel only.
|
||||
@@ -1308,6 +1247,8 @@ const char * pcTimerGetTimerName( TimerHandle_t xTimer ); /*lint !e971 Unqualifi
|
||||
BaseType_t xTimerCreateTimerTask( void ) PRIVILEGED_FUNCTION;
|
||||
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -32,6 +32,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
iflag_free = 1, //Buffer is not read and given back by application, free to overwrite
|
||||
iflag_dummydata = 2, //Data from here to end of ringbuffer is dummy. Restart reading at start of ringbuffer.
|
||||
iflag_wrap = 4, //Valid for RINGBUF_TYPE_ALLOWSPLIT, indicating that rest of the data is wrapped around
|
||||
} itemflag_t;
|
||||
|
||||
|
||||
@@ -53,6 +54,7 @@ struct ringbuf_t {
|
||||
BaseType_t (*copyItemToRingbufImpl)(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size);
|
||||
uint8_t *(*getItemFromRingbufImpl)(ringbuf_t *rb, size_t *length, int wanted_length);
|
||||
void (*returnItemToRingbufImpl)(ringbuf_t *rb, void *item);
|
||||
size_t (*getFreeSizeImpl)(ringbuf_t *rb);
|
||||
};
|
||||
|
||||
|
||||
@@ -82,7 +84,6 @@ static int ringbufferFreeMem(ringbuf_t *rb)
|
||||
return free_size-1;
|
||||
}
|
||||
|
||||
|
||||
//Copies a single item to the ring buffer; refuses to split items. Assumes there is space in the ringbuffer and
|
||||
//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
|
||||
//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
|
||||
@@ -203,6 +204,9 @@ static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, si
|
||||
if (buffer_size == 0) {
|
||||
rb->write_ptr=rb->data;
|
||||
return pdTRUE;
|
||||
} else {
|
||||
/* Indicate the wrapping */
|
||||
hdr->flags|=iflag_wrap;
|
||||
}
|
||||
} else {
|
||||
//Huh, only the header fit. Mark as dummy so the receive function doesn't receive
|
||||
@@ -359,6 +363,7 @@ static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
|
||||
configASSERT((hdr->flags & iflag_dummydata)==0);
|
||||
configASSERT((hdr->flags & iflag_free)==0);
|
||||
//Mark the buffer as free.
|
||||
hdr->flags&=~iflag_wrap;
|
||||
hdr->flags|=iflag_free;
|
||||
|
||||
//Do a cleanup pass.
|
||||
@@ -415,6 +420,67 @@ void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
|
||||
}
|
||||
|
||||
|
||||
size_t xRingbufferGetCurFreeSize(RingbufHandle_t ringbuf)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
configASSERT(rb);
|
||||
configASSERT(rb->getFreeSizeImpl);
|
||||
int free_size = rb->getFreeSizeImpl(rb);
|
||||
//Reserve one byte. If we do not do this and the entire buffer is filled, we get a situation
|
||||
//where read_ptr == free_ptr, messing up the next calculation.
|
||||
return free_size - 1;
|
||||
}
|
||||
|
||||
static size_t getCurFreeSizeByteBuf(ringbuf_t *rb)
|
||||
{
|
||||
//Return whatever space is available depending on relative positions of
|
||||
//the free pointer and write pointer. There is no overhead of headers in
|
||||
//this mode
|
||||
int free_size = rb->free_ptr-rb->write_ptr;
|
||||
if (free_size <= 0)
|
||||
free_size += rb->size;
|
||||
return free_size;
|
||||
}
|
||||
|
||||
static size_t getCurFreeSizeAllowSplit(ringbuf_t *rb)
|
||||
{
|
||||
int free_size;
|
||||
//If Both, the write and free pointer are at the start. Hence, the entire buffer
|
||||
//is available (minus the space for the header)
|
||||
if (rb->write_ptr == rb->free_ptr && rb->write_ptr == rb->data) {
|
||||
free_size = rb->size - sizeof(buf_entry_hdr_t);
|
||||
} else if (rb->write_ptr < rb->free_ptr) {
|
||||
//Else if the free pointer is beyond the write pointer, only the space between
|
||||
//them would be available (minus the space for the header)
|
||||
free_size = rb->free_ptr - rb->write_ptr - sizeof(buf_entry_hdr_t);
|
||||
} else {
|
||||
//Else the data can wrap around and 2 headers will be required
|
||||
free_size = rb->free_ptr - rb->write_ptr + rb->size - (2 * sizeof(buf_entry_hdr_t));
|
||||
}
|
||||
return free_size;
|
||||
}
|
||||
|
||||
static size_t getCurFreeSizeNoSplit(ringbuf_t *rb)
|
||||
{
|
||||
int free_size;
|
||||
//If the free pointer is beyond the write pointer, only the space between
|
||||
//them would be available
|
||||
if (rb->write_ptr < rb->free_ptr) {
|
||||
free_size = rb->free_ptr - rb->write_ptr;
|
||||
} else {
|
||||
//Else check which one is bigger amongst the below 2
|
||||
//1) Space from the write pointer to the end of buffer
|
||||
int size1 = rb->data + rb->size - rb->write_ptr;
|
||||
//2) Space from the start of buffer to the free pointer
|
||||
int size2 = rb->free_ptr - rb->data;
|
||||
//And then select the larger of the two
|
||||
free_size = size1 > size2 ? size1 : size2;
|
||||
}
|
||||
//In any case, a single header will be used, so subtracting the space that
|
||||
//would be required for it
|
||||
return free_size - sizeof(buf_entry_hdr_t);
|
||||
}
|
||||
|
||||
|
||||
RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
|
||||
{
|
||||
@@ -437,6 +503,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
|
||||
rb->returnItemToRingbufImpl=returnItemToRingbufDefault;
|
||||
//Calculate max item size. Worst case, we need to split an item into two, which means two headers of overhead.
|
||||
rb->maxItemSize=rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
|
||||
rb->getFreeSizeImpl=getCurFreeSizeAllowSplit;
|
||||
} else if (type==RINGBUF_TYPE_BYTEBUF) {
|
||||
rb->flags|=flag_bytebuf;
|
||||
rb->copyItemToRingbufImpl=copyItemToRingbufByteBuf;
|
||||
@@ -444,6 +511,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
|
||||
rb->returnItemToRingbufImpl=returnItemToRingbufBytebuf;
|
||||
//Calculate max item size. We have no headers and can split anywhere -> size is total size minus one.
|
||||
rb->maxItemSize=rb->size-1;
|
||||
rb->getFreeSizeImpl=getCurFreeSizeByteBuf;
|
||||
} else if (type==RINGBUF_TYPE_NOSPLIT) {
|
||||
rb->copyItemToRingbufImpl=copyItemToRingbufNoSplit;
|
||||
rb->getItemFromRingbufImpl=getItemFromRingbufDefault;
|
||||
@@ -453,6 +521,7 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
|
||||
//(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
|
||||
//with the real item. (item size being header+data)
|
||||
rb->maxItemSize=(rb->size/2)-sizeof(buf_entry_hdr_t)-4;
|
||||
rb->getFreeSizeImpl=getCurFreeSizeNoSplit;
|
||||
} else {
|
||||
configASSERT(0);
|
||||
}
|
||||
@@ -472,6 +541,12 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RingbufHandle_t xRingbufferCreateNoSplit(size_t item_size, size_t num_item)
|
||||
{
|
||||
size_t aligned_size = (item_size+3)&~3;
|
||||
return xRingbufferCreate((aligned_size + sizeof(buf_entry_hdr_t)) * num_item, RINGBUF_TYPE_NOSPLIT);
|
||||
}
|
||||
|
||||
void vRingbufferDelete(RingbufHandle_t ringbuf) {
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
if (rb) {
|
||||
@@ -489,6 +564,15 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf)
|
||||
return rb->maxItemSize;
|
||||
}
|
||||
|
||||
bool xRingbufferIsNextItemWrapped(RingbufHandle_t ringbuf)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
configASSERT(rb);
|
||||
buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->read_ptr;
|
||||
return hdr->flags & iflag_wrap;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
|
||||
{
|
||||
ringbuf_t *rb=(ringbuf_t *)ringbuf;
|
||||
|
@@ -541,6 +541,12 @@ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
|
||||
|
||||
#endif
|
||||
|
||||
//Function to call the Thread Local Storage Pointer Deletion Callbacks. Will be
|
||||
//called during task deletion before prvDeleteTCB is called.
|
||||
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
||||
static void prvDeleteTLS( TCB_t *pxTCB );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used only by the idle task. This checks to see if anything has been placed
|
||||
* in the list of tasks waiting to be deleted. If so the task is cleaned up
|
||||
@@ -1201,19 +1207,25 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
void vTaskDelete( TaskHandle_t xTaskToDelete )
|
||||
{
|
||||
//The following vTaskDelete() is backported from FreeRTOS v9.0.0 and modified for SMP.
|
||||
//v9.0.0 vTaskDelete() will immediately free task memory if the task being deleted is
|
||||
//NOT currently running and not pinned to the other core. Otherwise, freeing of task memory
|
||||
//will still be delegated to the Idle Task.
|
||||
|
||||
TCB_t *pxTCB;
|
||||
int core = xPortGetCoreID(); //Current core
|
||||
UBaseType_t free_now; //Flag to indicate if task memory can be freed immediately
|
||||
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
{
|
||||
/* If null is passed in here then it is the calling task that is
|
||||
being deleted. */
|
||||
pxTCB = prvGetTCBFromHandle( xTaskToDelete );
|
||||
|
||||
/* Remove task from the ready list and place in the termination list.
|
||||
This will stop the task from be scheduled. The idle task will check
|
||||
the termination list and free up any memory allocated by the
|
||||
scheduler for the TCB and stack. */
|
||||
/* Remove task from the ready list. */
|
||||
if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )
|
||||
{
|
||||
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
||||
@@ -1233,6 +1245,22 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Increment the uxTaskNumber also so kernel aware debuggers can
|
||||
detect that the task lists need re-generating. This is done before
|
||||
portPRE_TASK_DELETE_HOOK() as in the Windows port that macro will
|
||||
not return. */
|
||||
uxTaskNumber++;
|
||||
|
||||
//If task to be deleted is currently running on either core or is pinned to the other core. Let Idle free memory
|
||||
if( pxTCB == pxCurrentTCB[ core ] ||
|
||||
(portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !core ]) ||
|
||||
(portNUM_PROCESSORS > 1 && pxTCB->xCoreID == (!core)) )
|
||||
{
|
||||
/* Deleting a currently running task. This cannot complete
|
||||
within the task itself, as a context switch to another task is
|
||||
required. Place the task in the termination list. The idle task
|
||||
will check the termination list and free up any memory allocated
|
||||
by the scheduler for the TCB and stack of the deleted task. */
|
||||
vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
|
||||
|
||||
/* Increment the ucTasksDeleted variable so the idle task knows
|
||||
@@ -1240,22 +1268,44 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
check the xTasksWaitingTermination list. */
|
||||
++uxTasksDeleted;
|
||||
|
||||
/* Increment the uxTaskNumberVariable also so kernel aware debuggers
|
||||
can detect that the task lists need re-generating. */
|
||||
uxTaskNumber++;
|
||||
/* The pre-delete hook is primarily for the Windows simulator,
|
||||
in which Windows specific clean up operations are performed,
|
||||
after which it is not possible to yield away from this task -
|
||||
hence xYieldPending is used to latch that a context switch is
|
||||
required. */
|
||||
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
|
||||
|
||||
free_now = pdFALSE; //Let Idle Task free task memory
|
||||
}
|
||||
else //Task is not currently running and not pinned to the other core
|
||||
{
|
||||
--uxCurrentNumberOfTasks;
|
||||
|
||||
/* Reset the next expected unblock time in case it referred to
|
||||
the task that has just been deleted. */
|
||||
prvResetNextTaskUnblockTime();
|
||||
free_now = pdTRUE; //Set flag to free task memory immediately
|
||||
}
|
||||
|
||||
traceTASK_DELETE( pxTCB );
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
if(free_now == pdTRUE){ //Free task memory. Outside critical section due to deletion callbacks
|
||||
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
||||
prvDeleteTLS( pxTCB ); //Run deletion callbacks before deleting TCB
|
||||
#endif
|
||||
prvDeleteTCB( pxTCB ); //Must only be called after del cb
|
||||
}
|
||||
|
||||
/* Force a reschedule if it is the currently running task that has just
|
||||
been deleted. */
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
//No mux; no harm done if this misfires. The deleted task won't get scheduled anyway.
|
||||
if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
|
||||
if( pxTCB == pxCurrentTCB[ core ] ) //If task was currently running on this core
|
||||
{
|
||||
configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 );
|
||||
configASSERT( uxSchedulerSuspended[ core ] == 0 );
|
||||
|
||||
/* The pre-delete hook is primarily for the Windows simulator,
|
||||
in which Windows specific clean up operations are performed,
|
||||
@@ -1265,20 +1315,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[xPortGetCoreID()] );
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
else if ( portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !xPortGetCoreID() ] )
|
||||
else if ( portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !core] ) //If task was currently running on the other core
|
||||
{
|
||||
/* if task is running on the other CPU, force a yield on that CPU to take it off */
|
||||
vPortYieldOtherCore( !xPortGetCoreID() );
|
||||
vPortYieldOtherCore( !core );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Reset the next expected unblock time in case it referred to
|
||||
the task that has just been deleted. */
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
{
|
||||
prvResetNextTaskUnblockTime();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3583,52 +3627,53 @@ static void prvCheckTasksWaitingTermination( void )
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
{
|
||||
BaseType_t xListIsEmpty;
|
||||
int core = xPortGetCoreID();
|
||||
|
||||
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
||||
too often in the idle task. */
|
||||
while(uxTasksDeleted > ( UBaseType_t ) 0U )
|
||||
{
|
||||
TCB_t *pxTCB = NULL;
|
||||
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
{
|
||||
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
|
||||
}
|
||||
|
||||
if( xListIsEmpty == pdFALSE )
|
||||
{
|
||||
{
|
||||
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
|
||||
/* We only want to kill tasks that ran on this core because e.g. _xt_coproc_release needs to
|
||||
be called on the core the process is pinned on, if any */
|
||||
if( pxTCB->xCoreID == tskNO_AFFINITY || pxTCB->xCoreID == xPortGetCoreID()) {
|
||||
( void ) uxListRemove( &( pxTCB->xGenericListItem ) );
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxTasksDeleted;
|
||||
} else {
|
||||
/* Need to wait until the idle task on the other processor kills that task first. */
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
ListItem_t *target = listGET_HEAD_ENTRY(&xTasksWaitingTermination);
|
||||
for( ; target != listGET_END_MARKER(&xTasksWaitingTermination); target = listGET_NEXT(target) ){ //Walk the list
|
||||
TCB_t *tgt_tcb = ( TCB_t * )listGET_LIST_ITEM_OWNER(target);
|
||||
int affinity = tgt_tcb->xCoreID;
|
||||
//Self deleting tasks are added to Termination List before they switch context. Ensure they aren't still currently running
|
||||
if( pxCurrentTCB[core] == tgt_tcb || (portNUM_PROCESSORS > 1 && pxCurrentTCB[!core] == tgt_tcb) ){
|
||||
continue; //Can't free memory of task that is still running
|
||||
}
|
||||
if(affinity == core || affinity == tskNO_AFFINITY){ //Find first item not pinned to other core
|
||||
pxTCB = tgt_tcb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
if(pxTCB != NULL){
|
||||
( void ) uxListRemove( target ); //Remove list item from list
|
||||
--uxCurrentNumberOfTasks;
|
||||
--uxTasksDeleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex); //Need to call deletion callbacks outside critical section
|
||||
|
||||
if (pxTCB != NULL) { //Call deletion callbacks and free TCB memory
|
||||
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
||||
int x;
|
||||
for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
||||
{
|
||||
if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL)
|
||||
{
|
||||
pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]);
|
||||
}
|
||||
}
|
||||
prvDeleteTLS( pxTCB );
|
||||
#endif
|
||||
prvDeleteTCB( pxTCB );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
break; //No TCB found that could be freed by this core, break out of loop
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3831,7 +3876,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
||||
|
||||
#if ( INCLUDE_vTaskDelete == 1 )
|
||||
|
||||
|
||||
static void prvDeleteTCB( TCB_t *pxTCB )
|
||||
{
|
||||
/* Free up the memory allocated by the scheduler for the task. It is up
|
||||
@@ -3886,6 +3930,23 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
||||
#endif /* INCLUDE_vTaskDelete */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
||||
|
||||
static void prvDeleteTLS( TCB_t *pxTCB )
|
||||
{
|
||||
configASSERT( pxTCB );
|
||||
for( int x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
||||
{
|
||||
if (pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] != NULL) //If del cb is set
|
||||
{
|
||||
pxTCB->pvThreadLocalStoragePointersDelCallback[ x ](x, pxTCB->pvThreadLocalStoragePointers[ x ]); //Call del cb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) && ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvResetNextTaskUnblockTime( void )
|
||||
{
|
||||
TCB_t *pxTCB;
|
||||
|
@@ -1,26 +1,83 @@
|
||||
/*
|
||||
* Test backported deletion behavior by creating tasks of various affinities and
|
||||
* check if the task memory is freed immediately under the correct conditions.
|
||||
*
|
||||
* The behavior of vTaskDelete() has been backported form FreeRTOS v9.0.0. This
|
||||
* results in the immediate freeing of task memory and the immediate execution
|
||||
* of deletion callbacks under the following conditions...
|
||||
* - When deleting a task that is not currently running on either core
|
||||
* - When deleting a task that is pinned to the same core (with respect to
|
||||
* the core that calls vTaskDelete()
|
||||
*
|
||||
* If the two conditions are not met, freeing of task memory and execution of
|
||||
* deletion callbacks will still be carried out by the Idle Task.
|
||||
*/
|
||||
#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 "esp_heap_caps.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
static void task_delete_self(void *param)
|
||||
#define NO_OF_TSKS 3
|
||||
#define DELAY_TICKS 2
|
||||
#define HEAP_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_DEFAULT)
|
||||
|
||||
#define DELAY_US_ITERATIONS 1000
|
||||
|
||||
|
||||
static void tsk_self_del(void *param)
|
||||
{
|
||||
printf("Task %p running on core %d. Deleting shortly...\n", xTaskGetCurrentTaskHandle(), xPortGetCoreID());
|
||||
vTaskDelay(5);
|
||||
vTaskDelete(NULL); //Deleting self means deleting currently running task
|
||||
}
|
||||
|
||||
static void tsk_extern_del(void *param)
|
||||
{
|
||||
vTaskDelay(portMAX_DELAY); //Await external deletion
|
||||
}
|
||||
|
||||
static void tsk_self_del_us_delay(void *param)
|
||||
{
|
||||
uint32_t delay = (uint32_t)param;
|
||||
ets_delay_us(delay);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
|
||||
{
|
||||
/* -------------- Test vTaskDelete() on currently running tasks ----------------*/
|
||||
uint32_t before_count = uxTaskGetNumberOfTasks();
|
||||
|
||||
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);
|
||||
TEST_ASSERT_EQUAL(before_count + 2, uxTaskGetNumberOfTasks());
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks());
|
||||
uint32_t before_heap = heap_caps_get_free_size(HEAP_CAPS);
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){
|
||||
for(int j = 0; j < NO_OF_TSKS; j++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_self_del, "tsk_self", 1024, NULL, configMAX_PRIORITIES - 1, NULL, i));
|
||||
}
|
||||
}
|
||||
vTaskDelay(DELAY_TICKS); //Minimal delay to see if Idle task cleans up all tasks awaiting deletion in a single tick
|
||||
TEST_ASSERT_EQUAL(before_count, uxTaskGetNumberOfTasks());
|
||||
TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
|
||||
|
||||
/* ------------- Test vTaskDelete() on not currently running tasks ------------ */
|
||||
TaskHandle_t handles[NO_OF_TSKS];
|
||||
before_heap = heap_caps_get_free_size(HEAP_CAPS);
|
||||
//Create task pinned to the same core that will not run during task deletion
|
||||
for(int j = 0 ; j < NO_OF_TSKS; j++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(tsk_extern_del, "tsk_extern", 4096, NULL, configMAX_PRIORITIES - 1, &handles[j], xPortGetCoreID()));
|
||||
}
|
||||
TEST_ASSERT_NOT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS)); //Check tasks have been created
|
||||
//Delete the tasks, memory should be freed immediately
|
||||
for(int j = 0; j < NO_OF_TSKS; j++){
|
||||
vTaskDelete(handles[j]);
|
||||
}
|
||||
TEST_ASSERT_EQUAL(before_heap, heap_caps_get_free_size(HEAP_CAPS));
|
||||
|
||||
/* Test self deleting no affinity task is not removed by idle task of other core before context switch */
|
||||
for(int i = 0; i < DELAY_US_ITERATIONS; i+= 10){
|
||||
vTaskDelay(1); //Sync to next tick interrupt
|
||||
xTaskCreatePinnedToCore(tsk_self_del_us_delay, "delay", 1024, (void *)i, UNITY_FREERTOS_PRIORITY - 1, NULL, tskNO_AFFINITY);
|
||||
ets_delay_us(10); //Busy wait to ensure no affinity task runs on opposite core
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -373,11 +373,11 @@ static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t s
|
||||
record_free(p, callers);
|
||||
}
|
||||
heap_trace_record_t rec = {
|
||||
.address = p,
|
||||
.address = r,
|
||||
.ccount = ccount,
|
||||
.size = size,
|
||||
};
|
||||
memcpy(rec.alloced_by, callers, sizeof(heap_trace_record_t) * STACK_DEPTH);
|
||||
memcpy(rec.alloced_by, callers, sizeof(void *) * STACK_DEPTH);
|
||||
record_allocation(&rec);
|
||||
}
|
||||
return r;
|
||||
|
@@ -24,11 +24,11 @@ extern "C" {
|
||||
/* Please use heap_caps_malloc() instead of this function */
|
||||
void *pvPortMallocCaps(size_t xWantedSize, uint32_t caps) asm("heap_caps_malloc") __attribute__((deprecated));
|
||||
|
||||
/* Please use heap_caps_get_minimum_free_heap_size() instead of this function */
|
||||
size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps ) asm("heap_caps_get_minimum_free_heap_size") __attribute__((deprecated));
|
||||
/* Please use heap_caps_get_minimum_free_size() instead of this function */
|
||||
size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps ) asm("heap_caps_get_minimum_free_size") __attribute__((deprecated));
|
||||
|
||||
/* Please use heap_caps_get_free_size() instead of this function */
|
||||
size_t xPortGetFreeHeapSizeCaps( uint32_t caps ) asm("heap_caps_get_free_heap_size") __attribute__((deprecated));
|
||||
size_t xPortGetFreeHeapSizeCaps( uint32_t caps ) asm("heap_caps_get_free_size") __attribute__((deprecated));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2009 Dave Gamble
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -28,108 +28,211 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 6
|
||||
#define CJSON_VERSION_PATCH 0
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_False 0
|
||||
#define cJSON_True 1
|
||||
#define cJSON_NULL 2
|
||||
#define cJSON_Number 3
|
||||
#define cJSON_String 4
|
||||
#define cJSON_Array 5
|
||||
#define cJSON_Object 6
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON {
|
||||
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
int type; /* The type of the item, as above. */
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
char *valuestring; /* The item's string, if type==cJSON_String */
|
||||
int valueint; /* The item's number, if type==cJSON_Number */
|
||||
double valuedouble; /* The item's number, if type==cJSON_Number */
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks {
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
void *(*malloc_fn)(size_t sz);
|
||||
void (*free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type __stdcall
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall
|
||||
#endif
|
||||
#else /* !WIN32 */
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
extern char *cJSON_Print(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
|
||||
extern char *cJSON_PrintUnformatted(cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
extern void cJSON_Delete(cJSON *c);
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
extern int cJSON_GetArraySize(cJSON *array);
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
|
||||
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
|
||||
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
extern const char *cJSON_GetErrorPtr(void);
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
extern cJSON *cJSON_CreateNull(void);
|
||||
extern cJSON *cJSON_CreateTrue(void);
|
||||
extern cJSON *cJSON_CreateFalse(void);
|
||||
extern cJSON *cJSON_CreateBool(int b);
|
||||
extern cJSON *cJSON_CreateNumber(double num);
|
||||
extern cJSON *cJSON_CreateDouble(double num,int i_num);
|
||||
extern cJSON *cJSON_CreateString(const char *string);
|
||||
extern cJSON *cJSON_CreateArray(void);
|
||||
extern cJSON *cJSON_CreateObject(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* These utilities create an Array of count items. */
|
||||
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
|
||||
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
|
||||
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
|
||||
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
|
||||
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */
|
||||
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
|
||||
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
|
||||
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
|
||||
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
|
||||
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
|
||||
|
||||
extern void cJSON_Minify(char *json);
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Macros for creating things quickly. */
|
||||
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
|
||||
@@ -138,10 +241,20 @@ extern void cJSON_Minify(char *json);
|
||||
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
|
||||
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
|
||||
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
|
||||
#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,40 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
|
||||
cJSON *cJSONUtils_GetPointer(cJSON *object,const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
|
||||
|
||||
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
|
||||
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to);
|
||||
void cJSONUtils_AddPatchToArray(cJSON *array,const char *op,const char *path,cJSON *val); /* Utility for generating patch array entries. */
|
||||
int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches); /* Returns 0 for success. */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
/* Utility for generating patch array entries. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
|
||||
/* Returns 0 for success. */
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
|
||||
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
|
||||
|
||||
/*
|
||||
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
|
||||
@@ -14,17 +42,33 @@ int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches); /* Returns 0 for succ
|
||||
//{
|
||||
// cJSON *modme = cJSON_Duplicate(*object, 1);
|
||||
// int error = cJSONUtils_ApplyPatches(modme, patches);
|
||||
// if (!error) {cJSON_Delete(*object);*object=modme;}
|
||||
// else cJSON_Delete(modme);
|
||||
// if (!error)
|
||||
// {
|
||||
// cJSON_Delete(*object);
|
||||
// *object = modme;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cJSON_Delete(modme);
|
||||
// }
|
||||
//
|
||||
// return error;
|
||||
//}
|
||||
// Code not added to library since this strategy is a LOT slower.
|
||||
*/
|
||||
|
||||
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
|
||||
cJSON* cJSONUtils_MergePatch(cJSON *target, cJSON *patch); /* target will be modified by patch. return value is new ptr for target. */
|
||||
cJSON *cJSONUtils_GenerateMergePatch(cJSON *from,cJSON *to); /* generates a patch to move from -> to */
|
||||
/* target will be modified by patch. return value is new ptr for target. */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
|
||||
/* generates a patch to move from -> to */
|
||||
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
|
||||
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
|
||||
|
||||
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target); /* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
/* Given a root object and a target object, construct a pointer from one to the other. */
|
||||
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
|
||||
|
||||
void cJSONUtils_SortObject(cJSON *object); /* Sorts the members of the object into alphabetical order. */
|
||||
/* Sorts the members of the object into alphabetical order. */
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
|
||||
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
|
||||
|
@@ -11,6 +11,12 @@
|
||||
// WITHOUT 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_DEBUG_H_
|
||||
#define _ESP_DEBUG_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||
@@ -43,3 +49,9 @@ void mbedtls_esp_disable_debug_log(mbedtls_ssl_config *conf);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_DEBUG_H__ */
|
||||
|
@@ -569,7 +569,8 @@ static const uint8_t * _mdns_read_fqdn(const uint8_t * packet, const uint8_t * s
|
||||
&& (strcmp(buf, MDNS_DEFAULT_DOMAIN) != 0)
|
||||
&& (strcmp(buf, "ip6") != 0)
|
||||
&& (strcmp(buf, "in-addr") != 0)) {
|
||||
snprintf((char*)name, MDNS_NAME_BUF_LEN, "%s.%s", name->host, buf);
|
||||
strlcat(name->host, ".", sizeof(name->host));
|
||||
strlcat(name->host, buf, sizeof(name->host));
|
||||
} else if (strcmp(buf, MDNS_SUB_STR) == 0) {
|
||||
name->sub = 1;
|
||||
} else {
|
||||
|
@@ -42,7 +42,7 @@
|
||||
#endif
|
||||
|
||||
#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 )
|
||||
#define WITH_FRC1 1
|
||||
#define WITH_FRC 1
|
||||
#endif
|
||||
|
||||
#ifdef WITH_RTC
|
||||
@@ -72,19 +72,21 @@ static uint64_t get_rtc_time_us()
|
||||
// s_boot_time: time from Epoch to the first boot time
|
||||
#ifdef WITH_RTC
|
||||
// when RTC is used to persist time, two RTC_STORE registers are used to store boot time
|
||||
#elif defined(WITH_FRC1)
|
||||
#elif defined(WITH_FRC)
|
||||
static uint64_t s_boot_time;
|
||||
#endif
|
||||
#endif // WITH_RTC
|
||||
|
||||
#if defined(WITH_RTC) || defined(WITH_FRC1)
|
||||
#if defined(WITH_RTC) || defined(WITH_FRC)
|
||||
static _lock_t s_boot_time_lock;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_RTC
|
||||
// Offset between FRC timer and the RTC.
|
||||
// Initialized after reset or light sleep.
|
||||
#if defined(WITH_RTC) && defined(WITH_FRC)
|
||||
uint64_t s_microseconds_offset;
|
||||
#endif
|
||||
|
||||
#if defined(WITH_RTC) || defined(WITH_FRC1)
|
||||
#if defined(WITH_RTC) || defined(WITH_FRC)
|
||||
static void set_boot_time(uint64_t time_us)
|
||||
{
|
||||
_lock_acquire(&s_boot_time_lock);
|
||||
@@ -109,7 +111,7 @@ static uint64_t get_boot_time()
|
||||
_lock_release(&s_boot_time_lock);
|
||||
return result;
|
||||
}
|
||||
#endif //defined(WITH_RTC) || defined(WITH_FRC1)
|
||||
#endif //defined(WITH_RTC) || defined(WITH_FRC)
|
||||
|
||||
|
||||
void esp_clk_slowclk_cal_set(uint32_t new_cal)
|
||||
@@ -139,10 +141,10 @@ uint32_t esp_clk_slowclk_cal_get()
|
||||
|
||||
void esp_set_time_from_rtc()
|
||||
{
|
||||
#if defined( WITH_FRC1 ) && defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) && defined( WITH_RTC )
|
||||
// initialize time from RTC clock
|
||||
s_microseconds_offset = get_rtc_time_us() - esp_timer_get_time();
|
||||
#endif // WITH_FRC1 && WITH_RTC
|
||||
#endif // WITH_FRC && WITH_RTC
|
||||
}
|
||||
|
||||
uint64_t esp_clk_rtc_time(void)
|
||||
@@ -166,23 +168,27 @@ clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms)
|
||||
return (clock_t) tv.tv_sec;
|
||||
}
|
||||
|
||||
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
static uint64_t get_time_since_boot()
|
||||
{
|
||||
uint64_t microseconds = 0;
|
||||
#ifdef WITH_FRC1
|
||||
#ifdef WITH_FRC
|
||||
#ifdef WITH_RTC
|
||||
microseconds = s_microseconds_offset + esp_timer_get_time();
|
||||
#else
|
||||
microseconds = esp_timer_get_time();
|
||||
#endif // WITH_RTC
|
||||
#elif defined(WITH_RTC)
|
||||
microseconds = get_rtc_time_us();
|
||||
#endif
|
||||
#endif // WITH_FRC
|
||||
return microseconds;
|
||||
}
|
||||
#endif // defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#endif // defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
|
||||
int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
|
||||
{
|
||||
(void) tz;
|
||||
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
if (tv) {
|
||||
uint64_t microseconds = get_boot_time() + get_time_since_boot();
|
||||
tv->tv_sec = microseconds / 1000000;
|
||||
@@ -192,13 +198,13 @@ int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz)
|
||||
#else
|
||||
__errno_r(r) = ENOSYS;
|
||||
return -1;
|
||||
#endif // defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#endif // defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval *tv, const struct timezone *tz)
|
||||
{
|
||||
(void) tz;
|
||||
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
if (tv) {
|
||||
uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec;
|
||||
uint64_t since_boot = get_time_since_boot();
|
||||
@@ -233,7 +239,7 @@ unsigned int sleep(unsigned int seconds)
|
||||
|
||||
uint32_t system_get_time(void)
|
||||
{
|
||||
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
return get_time_since_boot();
|
||||
#else
|
||||
return 0;
|
||||
@@ -244,7 +250,7 @@ uint32_t system_get_current_time(void) __attribute__((alias("system_get_time")))
|
||||
|
||||
uint32_t system_relative_time(uint32_t current_time)
|
||||
{
|
||||
#if defined( WITH_FRC1 ) || defined( WITH_RTC )
|
||||
#if defined( WITH_FRC ) || defined( WITH_RTC )
|
||||
return get_time_since_boot() - current_time;
|
||||
#else
|
||||
return 0;
|
||||
|
@@ -62,7 +62,7 @@ void HashList::insert(const Item& item, size_t index)
|
||||
|
||||
void HashList::erase(size_t index)
|
||||
{
|
||||
for (auto it = std::begin(mBlockList); it != std::end(mBlockList);) {
|
||||
for (auto it = mBlockList.begin(); it != mBlockList.end();) {
|
||||
bool haveEntries = false;
|
||||
for (size_t i = 0; i < it->mCount; ++i) {
|
||||
if (it->mNodes[i].mIndex == index) {
|
||||
@@ -88,7 +88,7 @@ void HashList::erase(size_t index)
|
||||
size_t HashList::find(size_t start, const Item& item)
|
||||
{
|
||||
const uint32_t hash_24 = item.calculateCrc32WithoutValue() & 0xffffff;
|
||||
for (auto it = std::begin(mBlockList); it != std::end(mBlockList); ++it) {
|
||||
for (auto it = mBlockList.begin(); it != mBlockList.end(); ++it) {
|
||||
for (size_t index = 0; index < it->mCount; ++index) {
|
||||
HashListNode& e = it->mNodes[index];
|
||||
if (e.mIndex >= start &&
|
||||
|
@@ -154,7 +154,11 @@ int ssl_pm_new(SSL *ssl)
|
||||
}
|
||||
|
||||
if (ssl->ctx->ssl_alpn.alpn_status == ALPN_ENABLE) {
|
||||
#ifdef MBEDTLS_SSL_ALPN
|
||||
mbedtls_ssl_conf_alpn_protocols( &ssl_pm->conf, ssl->ctx->ssl_alpn.alpn_list );
|
||||
#else
|
||||
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "CONFIG_MBEDTLS_SSL_ALPN must be enabled to use ALPN", -1);
|
||||
#endif // MBEDTLS_SSL_ALPN
|
||||
}
|
||||
mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg);
|
||||
|
||||
|
@@ -149,13 +149,24 @@ void rtc_clk_init(rtc_clk_config_t cfg);
|
||||
/**
|
||||
* @brief Get main XTAL frequency
|
||||
*
|
||||
* This is the value passed to rtc_clk_init function, or if the value was
|
||||
* RTC_XTAL_FREQ_AUTO, the detected XTAL frequency.
|
||||
* This is the value stored in RTC register RTC_XTAL_FREQ_REG by the bootloader. As passed to
|
||||
* rtc_clk_init function, or if the value was RTC_XTAL_FREQ_AUTO, the detected
|
||||
* XTAL frequency.
|
||||
*
|
||||
* @return XTAL frequency, one of rtc_xtal_freq_t
|
||||
*/
|
||||
rtc_xtal_freq_t rtc_clk_xtal_freq_get();
|
||||
|
||||
/**
|
||||
* @brief Update XTAL frequency
|
||||
*
|
||||
* Updates the XTAL value stored in RTC_XTAL_FREQ_REG. Usually this value is ignored
|
||||
* after startup.
|
||||
*
|
||||
* @param xtal_freq New frequency value
|
||||
*/
|
||||
void rtc_clk_xtal_freq_update(rtc_xtal_freq_t xtal_freq);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable 32 kHz XTAL oscillator
|
||||
* @param en true to enable, false to disable
|
||||
|
@@ -1830,7 +1830,16 @@
|
||||
#define RTC_CNTL_SCRATCH7_V 0xFFFFFFFF
|
||||
#define RTC_CNTL_SCRATCH7_S 0
|
||||
|
||||
#define RTC_CNTL_DIAG0_REG (DR_REG_RTCCNTL_BASE + 0xc0)
|
||||
#define RTC_CNTL_LOW_POWER_ST_REG (DR_REG_RTCCNTL_BASE + 0xc0)
|
||||
/* RTC_CNTL_RDY_FOR_WAKEUP : R/0; bitpos:[19]; default: 0 */
|
||||
/*description: 1 if RTC controller is ready to execute WAKE instruction, 0 otherwise */
|
||||
#define RTC_CNTL_RDY_FOR_WAKEUP (BIT(19))
|
||||
#define RTC_CNTL_RDY_FOR_WAKEUP_M (BIT(19))
|
||||
#define RTC_CNTL_RDY_FOR_WAKEUP_V 0x1
|
||||
#define RTC_CNTL_RDY_FOR_WAKEUP_S 19
|
||||
|
||||
/* Compatibility definition */
|
||||
#define RTC_CNTL_DIAG0_REG RTC_CNTL_LOW_POWER_ST_REG
|
||||
/* RTC_CNTL_LOW_POWER_DIAG0 : RO ;bitpos:[31:0] ;default: 0 ; */
|
||||
/*description: */
|
||||
#define RTC_CNTL_LOW_POWER_DIAG0 0xFFFFFFFF
|
||||
|
@@ -112,6 +112,15 @@ static void test_clock_switching(void (*switch_func)(rtc_cpu_freq_t))
|
||||
ref_clock_deinit();
|
||||
}
|
||||
|
||||
TEST_CASE("Calculate 8M clock frequency", "[rtc_clk]")
|
||||
{
|
||||
// calibrate 8M/256 clock against XTAL, get 8M/256 clock period
|
||||
uint32_t rtc_8md256_period = rtc_clk_cal(RTC_CAL_8MD256, 100);
|
||||
uint32_t rtc_fast_freq_hz = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / rtc_8md256_period;
|
||||
printf("RTC_FAST_CLK=%d Hz\n", rtc_fast_freq_hz);
|
||||
TEST_ASSERT_INT32_WITHIN(500000, RTC_FAST_CLK_FREQ_APPROX, rtc_fast_freq_hz);
|
||||
}
|
||||
|
||||
TEST_CASE("Test switching between PLL and XTAL", "[rtc_clk]")
|
||||
{
|
||||
test_clock_switching(rtc_clk_cpu_freq_set);
|
||||
|
@@ -1,5 +1,36 @@
|
||||
menu "SPI Flash driver"
|
||||
|
||||
config SPI_FLASH_VERIFY_WRITE
|
||||
bool "Verify SPI flash writes"
|
||||
default n
|
||||
help
|
||||
If this option is enabled, any time SPI flash is written then the data will be read
|
||||
back and verified. This can catch hardware problems with SPI flash, or flash which
|
||||
was not erased before verification.
|
||||
|
||||
config SPI_FLASH_LOG_FAILED_WRITE
|
||||
bool "Log errors if verification fails"
|
||||
depends on SPI_FLASH_VERIFY_WRITE
|
||||
default n
|
||||
help
|
||||
If this option is enabled, if SPI flash write verification fails then a log error line
|
||||
will be written with the address, expected & actual values. This can be useful when
|
||||
debugging hardware SPI flash problems.
|
||||
|
||||
config SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
|
||||
bool "Log warning if writing zero bits to ones"
|
||||
depends on SPI_FLASH_VERIFY_WRITE
|
||||
default n
|
||||
help
|
||||
If this option is enabled, any SPI flash write which tries to set zero bits in the flash to
|
||||
ones will log a warning. Such writes will not result in the requested data appearing identically
|
||||
in flash once written, as SPI NOR flash can only set bits to one when an entire sector is erased.
|
||||
After erasing, individual bits can only be written from one to zero.
|
||||
|
||||
Note that some software (such as SPIFFS) which is aware of SPI NOR flash may write one bits as an
|
||||
optimisation, relying on the data in flash becoming a bitwise AND of the new data and any existing data.
|
||||
Such software will log spurious warnings if this option is enabled.
|
||||
|
||||
config SPI_FLASH_ENABLE_COUNTERS
|
||||
bool "Enable operation counters"
|
||||
default 0
|
||||
|
@@ -44,8 +44,9 @@
|
||||
#define MAX_WRITE_CHUNK 8192
|
||||
#define MAX_READ_CHUNK 16384
|
||||
|
||||
static const char *TAG __attribute__((unused)) = "spi_flash";
|
||||
|
||||
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
|
||||
static const char *TAG = "spi_flash";
|
||||
static spi_flash_counters_t s_flash_stats;
|
||||
|
||||
#define COUNTER_START() uint32_t ts_begin = xthal_get_ccount()
|
||||
@@ -233,6 +234,81 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
return spi_flash_translate_rc(rc);
|
||||
}
|
||||
|
||||
/* Wrapper around esp_rom_spiflash_write() that verifies data as written if CONFIG_SPI_FLASH_VERIFY_WRITE is set.
|
||||
|
||||
If CONFIG_SPI_FLASH_VERIFY_WRITE is not set, this is esp_rom_spiflash_write().
|
||||
*/
|
||||
static IRAM_ATTR esp_rom_spiflash_result_t spi_flash_write_inner(uint32_t target, const uint32_t *src_addr, int32_t len)
|
||||
{
|
||||
#ifndef CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||
return esp_rom_spiflash_write(target, src_addr, len);
|
||||
#else // CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||
esp_rom_spiflash_result_t res = ESP_ROM_SPIFLASH_RESULT_OK;
|
||||
assert(len % sizeof(uint32_t) == 0);
|
||||
|
||||
uint32_t before_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM / sizeof(uint32_t)];
|
||||
uint32_t after_buf[ESP_ROM_SPIFLASH_BUFF_BYTE_READ_NUM / sizeof(uint32_t)];
|
||||
int32_t remaining = len;
|
||||
for(int i = 0; i < len; i += sizeof(before_buf)) {
|
||||
int i_w = i / sizeof(uint32_t); // index in words (i is an index in bytes)
|
||||
|
||||
int32_t read_len = MIN(sizeof(before_buf), remaining);
|
||||
|
||||
// Read "before" contents from flash
|
||||
res = esp_rom_spiflash_read(target + i, before_buf, read_len);
|
||||
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
|
||||
for (int r = 0; r < read_len; r += sizeof(uint32_t)) {
|
||||
int r_w = r / sizeof(uint32_t); // index in words (r is index in bytes)
|
||||
|
||||
uint32_t write = src_addr[i_w + r_w];
|
||||
uint32_t before = before_buf[r_w];
|
||||
if ((before & write) != write) {
|
||||
spi_flash_guard_end();
|
||||
ESP_LOGW(TAG, "Write at offset 0x%x requests 0x%08x but will write 0x%08x -> 0x%08x",
|
||||
target + i + r, write, before, before & write);
|
||||
spi_flash_guard_start();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = esp_rom_spiflash_write(target + i, &src_addr[i_w], read_len);
|
||||
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
res = esp_rom_spiflash_read(target + i, after_buf, read_len);
|
||||
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (int r = 0; r < read_len; r += sizeof(uint32_t)) {
|
||||
int r_w = r / sizeof(uint32_t); // index in words (r is index in bytes)
|
||||
|
||||
uint32_t expected = src_addr[i_w + r_w] & before_buf[r_w];
|
||||
uint32_t actual = after_buf[r_w];
|
||||
if (expected != actual) {
|
||||
#ifdef CONFIG_SPI_FLASH_LOG_FAILED_WRITE
|
||||
spi_flash_guard_end();
|
||||
ESP_LOGE(TAG, "Bad write at offset 0x%x expected 0x%08x readback 0x%08x", target + i + r, expected, actual);
|
||||
spi_flash_guard_start();
|
||||
#endif
|
||||
res = ESP_ROM_SPIFLASH_RESULT_ERR;
|
||||
}
|
||||
}
|
||||
if (res != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
break;
|
||||
}
|
||||
remaining -= read_len;
|
||||
}
|
||||
return res;
|
||||
#endif // CONFIG_SPI_FLASH_VERIFY_WRITE
|
||||
}
|
||||
|
||||
|
||||
esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
||||
{
|
||||
CHECK_WRITE_ADDRESS(dst, size);
|
||||
@@ -269,7 +345,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
||||
uint32_t t = 0xffffffff;
|
||||
memcpy(((uint8_t *) &t) + (dst - left_off), srcc, left_size);
|
||||
spi_flash_guard_start();
|
||||
rc = esp_rom_spiflash_write(left_off, &t, 4);
|
||||
rc = spi_flash_write_inner(left_off, &t, 4);
|
||||
spi_flash_guard_end();
|
||||
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
goto out;
|
||||
@@ -296,7 +372,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
||||
write_src = (const uint8_t *)write_buf;
|
||||
}
|
||||
spi_flash_guard_start();
|
||||
rc = esp_rom_spiflash_write(dst + mid_off, (const uint32_t *) write_src, write_size);
|
||||
rc = spi_flash_write_inner(dst + mid_off, (const uint32_t *) write_src, write_size);
|
||||
spi_flash_guard_end();
|
||||
COUNTER_ADD_BYTES(write, write_size);
|
||||
mid_size -= write_size;
|
||||
@@ -311,7 +387,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
|
||||
uint32_t t = 0xffffffff;
|
||||
memcpy(&t, srcc + right_off, right_size);
|
||||
spi_flash_guard_start();
|
||||
rc = esp_rom_spiflash_write(dst + right_off, &t, 4);
|
||||
rc = spi_flash_write_inner(dst + right_off, &t, 4);
|
||||
spi_flash_guard_end();
|
||||
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
|
||||
goto out;
|
||||
|
@@ -88,6 +88,25 @@ config SPIFFS_USE_MAGIC_LENGTH
|
||||
configured and formatted for 4 megabytes will not be accepted
|
||||
for mounting with a configuration defining the filesystem as 2 megabytes.
|
||||
|
||||
config SPIFFS_META_LENGTH
|
||||
int "Size of per-file metadata field"
|
||||
default 4
|
||||
help
|
||||
This option sets the number of extra bytes stored in the file header.
|
||||
These bytes can be used in an application-specific manner.
|
||||
Set this to at least 4 bytes to enable support for saving file
|
||||
modification time.
|
||||
|
||||
config SPIFFS_USE_MTIME
|
||||
bool "Save file modification time"
|
||||
default "y"
|
||||
depends on SPIFFS_META_LENGTH >= 4
|
||||
help
|
||||
If enabled, then the first 4 bytes of per-file metadata will be used
|
||||
to store file modification time (mtime), accessible through
|
||||
stat/fstat functions.
|
||||
Modification time is updated when the file is opened.
|
||||
|
||||
menu "Debug Configuration"
|
||||
|
||||
config SPIFFS_DBG
|
||||
|
@@ -33,6 +33,10 @@
|
||||
|
||||
static const char * TAG = "SPIFFS";
|
||||
|
||||
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||
_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t),
|
||||
"SPIFFS_META_LENGTH size should be >= sizeof(time_t)");
|
||||
#endif //CONFIG_SPIFFS_USE_MTIME
|
||||
/**
|
||||
* @brief SPIFFS definition structure
|
||||
*/
|
||||
@@ -80,6 +84,8 @@ static long vfs_spiffs_telldir(void* ctx, DIR* pdir);
|
||||
static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset);
|
||||
static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode);
|
||||
static int vfs_spiffs_rmdir(void* ctx, const char* name);
|
||||
static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file f);
|
||||
static time_t vfs_spiffs_get_mtime(const spiffs_stat* s);
|
||||
|
||||
static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
|
||||
|
||||
@@ -507,12 +513,16 @@ static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode)
|
||||
{
|
||||
assert(path);
|
||||
esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
|
||||
int fd = SPIFFS_open(efs->fs, path, spiffs_mode_conv(flags), mode);
|
||||
int spiffs_flags = spiffs_mode_conv(flags);
|
||||
int fd = SPIFFS_open(efs->fs, path, spiffs_flags, mode);
|
||||
if (fd < 0) {
|
||||
errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
|
||||
SPIFFS_clearerr(efs->fs);
|
||||
return -1;
|
||||
}
|
||||
if (!(spiffs_flags & SPIFFS_RDONLY)) {
|
||||
vfs_spiffs_update_mtime(efs->fs, fd);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -562,7 +572,6 @@ static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode)
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
||||
@@ -578,6 +587,9 @@ static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
|
||||
}
|
||||
st->st_size = s.size;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
|
||||
st->st_mtime = vfs_spiffs_get_mtime(&s);
|
||||
st->st_atime = 0;
|
||||
st->st_ctime = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -597,6 +609,9 @@ static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
|
||||
st->st_size = s.size;
|
||||
st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
|
||||
st->st_mtime = vfs_spiffs_get_mtime(&s);
|
||||
st->st_atime = 0;
|
||||
st->st_ctime = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -764,3 +779,31 @@ static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2)
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file fd)
|
||||
{
|
||||
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||
time_t t = time(NULL);
|
||||
spiffs_stat s;
|
||||
int ret = SPIFFS_OK;
|
||||
if (CONFIG_SPIFFS_META_LENGTH > sizeof(t)) {
|
||||
ret = SPIFFS_fstat(fs, fd, &s);
|
||||
}
|
||||
if (ret == SPIFFS_OK) {
|
||||
memcpy(s.meta, &t, sizeof(t));
|
||||
ret = SPIFFS_fupdate_meta(fs, fd, s.meta);
|
||||
}
|
||||
if (ret != SPIFFS_OK) {
|
||||
ESP_LOGW(TAG, "Failed to update mtime (%d)", ret);
|
||||
}
|
||||
#endif //CONFIG_SPIFFS_USE_MTIME
|
||||
}
|
||||
|
||||
static time_t vfs_spiffs_get_mtime(const spiffs_stat* s)
|
||||
{
|
||||
time_t t = 0;
|
||||
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||
memcpy(&t, s->meta, sizeof(t));
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
@@ -158,7 +158,7 @@ extern void spiffs_api_unlock(struct spiffs_t *fs);
|
||||
// This is derived from following:
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||
#define SPIFFS_OBJ_META_LEN (0)
|
||||
#define SPIFFS_OBJ_META_LEN (CONFIG_SPIFFS_META_LENGTH)
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
|
@@ -505,3 +505,45 @@ TEST_CASE("multiple tasks can use same volume", "[spiffs]")
|
||||
test_spiffs_concurrent("/spiffs/f");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPIFFS_USE_MTIME
|
||||
TEST_CASE("mtime is updated when file is opened", "[spiffs]")
|
||||
{
|
||||
/* Open a file, check that mtime is set correctly */
|
||||
const char* filename = "/spiffs/time";
|
||||
test_setup();
|
||||
time_t t_before_create = time(NULL);
|
||||
test_spiffs_create_file_with_text(filename, "\n");
|
||||
time_t t_after_create = time(NULL);
|
||||
|
||||
struct stat st;
|
||||
TEST_ASSERT_EQUAL(0, stat(filename, &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT(st.st_mtime >= t_before_create
|
||||
&& st.st_mtime <= t_after_create);
|
||||
|
||||
/* Wait a bit, open again, check that mtime is updated */
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
time_t t_before_open = time(NULL);
|
||||
FILE *f = fopen(filename, "a");
|
||||
time_t t_after_open = time(NULL);
|
||||
TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT(st.st_mtime >= t_before_open
|
||||
&& st.st_mtime <= t_after_open);
|
||||
fclose(f);
|
||||
|
||||
/* Wait a bit, open for reading, check that mtime is not updated */
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
time_t t_before_open_ro = time(NULL);
|
||||
f = fopen(filename, "r");
|
||||
TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT(t_before_open_ro > t_after_open
|
||||
&& st.st_mtime >= t_before_open
|
||||
&& st.st_mtime <= t_after_open);
|
||||
fclose(f);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
#endif // CONFIG_SPIFFS_USE_MTIME
|
||||
|
@@ -18,6 +18,10 @@ In addition to the existing binutils port for the ESP32 ULP coprocessor, it is p
|
||||
|
||||
The ``program`` array is an array of ``ulp_insn_t``, i.e. ULP coprocessor instructions. Each ``I_XXX`` preprocessor define translates into a single 32-bit instruction. Arguments of these preprocessor defines can be register numbers (``R0 — R3``) and literal constants. See `ULP coprocessor instruction defines`_ section for descriptions of instructions and arguments they take.
|
||||
|
||||
.. note::
|
||||
|
||||
Because some of the instruction macros expand to inline function calls, defining such array in global scope will cause the compiler to produce an "initializer element is not constant" error. To fix this error, move the definition of instructions array into local scope.
|
||||
|
||||
Load and store instructions use addresses expressed in 32-bit words. Address 0 corresponds to the first word of ``RTC_SLOW_MEM`` (which is address 0x50000000 as seen by the main CPUs).
|
||||
|
||||
To generate branch instructions, special ``M_`` preprocessor defines are used. ``M_LABEL`` define can be used to define a branch target. Label identifier is a 16-bit integer. ``M_Bxxx`` defines can be used to generate branch instructions with target set to a particular label.
|
||||
|
@@ -266,9 +266,9 @@ _Static_assert(sizeof(ulp_insn_t) == 4, "ULP coprocessor instruction size should
|
||||
* Delay (nop) for a given number of cycles
|
||||
*/
|
||||
#define I_DELAY(cycles_) { .delay = {\
|
||||
.opcode = OPCODE_DELAY, \
|
||||
.cycles = cycles_, \
|
||||
.unused = 0, \
|
||||
.cycles = cycles_ } }
|
||||
.opcode = OPCODE_DELAY } }
|
||||
|
||||
/**
|
||||
* Halt the coprocessor.
|
||||
|
@@ -153,7 +153,17 @@ INPUT = \
|
||||
../components/esp32/include/esp_pm.h \
|
||||
../components/esp32/include/esp32/pm.h \
|
||||
### esp_timer, High Resolution Timer
|
||||
../components/esp32/include/esp_timer.h
|
||||
../components/esp32/include/esp_timer.h \
|
||||
###
|
||||
### FreeRTOS
|
||||
###
|
||||
../components/freertos/include/freertos/task.h \
|
||||
../components/freertos/include/freertos/queue.h \
|
||||
../components/freertos/include/freertos/semphr.h \
|
||||
../components/freertos/include/freertos/timers.h \
|
||||
../components/freertos/include/freertos/event_groups.h \
|
||||
../components/freertos/include/freertos/ringbuf.h
|
||||
|
||||
|
||||
|
||||
## Get warnings for functions that have no documentation for their parameters or return value
|
||||
@@ -165,7 +175,16 @@ WARN_NO_PARAMDOC = YES
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
PREDEFINED = __attribute__(x)=
|
||||
PREDEFINED = \
|
||||
__attribute__(x)= \
|
||||
IRAM_ATTR= \
|
||||
configSUPPORT_DYNAMIC_ALLOCATION=1 \
|
||||
configSUPPORT_STATIC_ALLOCATION=1 \
|
||||
configQUEUE_REGISTRY_SIZE=1 \
|
||||
configUSE_RECURSIVE_MUTEXES=1 \
|
||||
configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS=1 \
|
||||
configNUM_THREAD_LOCAL_STORAGE_POINTERS=1 \
|
||||
configUSE_APPLICATION_TASK_TAG=1
|
||||
|
||||
## Do not complain about not having dot
|
||||
##
|
||||
|
BIN
docs/_static/rmt-carrier.png
vendored
Normal file
BIN
docs/_static/rmt-carrier.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
docs/_static/rmt-waveform-modulated.png
vendored
Normal file
BIN
docs/_static/rmt-waveform-modulated.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
BIN
docs/_static/rmt-waveform.png
vendored
Normal file
BIN
docs/_static/rmt-waveform.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
@@ -156,7 +156,7 @@ Minimal Component Makefile
|
||||
|
||||
The minimal ``component.mk`` file is an empty file(!). If the file is empty, the default component behaviour is set:
|
||||
|
||||
- All source files in the same directory as the makefile (``*.c``, ``*.cpp``, ``*.S``) will be compiled into the component library
|
||||
- All source files in the same directory as the makefile (``*.c``, ``*.cpp``, ``*.cc``, ``*.S``) will be compiled into the component library
|
||||
- A sub-directory "include" will be added to the global include search path for all other components.
|
||||
- The component library will be linked into the project app.
|
||||
|
||||
@@ -321,6 +321,7 @@ Second Level: Component Makefiles
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Each call to a component makefile goes via the ``$(IDF_PATH)/make/component_wrapper.mk`` wrapper makefile.
|
||||
- This component wrapper includes all component ``Makefile.componentbuild`` files, making any recipes, variables etc in these files available to every component.
|
||||
- The ``component_wrapper.mk`` is called with the current directory set to the component build directory, and the ``COMPONENT_MAKEFILE`` variable is set to the absolute path to ``component.mk``.
|
||||
- ``component_wrapper.mk`` sets default values for all `component variables`, then includes the `component.mk` file which can override or modify these.
|
||||
- If ``COMPONENT_OWNBUILDTARGET`` and ``COMPONENT_OWNCLEANTARGET`` are not defined, default build and clean targets are created for the component's source files and the prerequisite ``COMPONENT_LIBRARY`` static library file.
|
||||
@@ -390,6 +391,15 @@ configuration options at the top-level of menuconfig, rather than inside the "Co
|
||||
|
||||
Take care when adding configuration values in this file, as they will be included across the entire project configuration. Where possible, it's generally better to create a KConfig file for `component configuration`.
|
||||
|
||||
|
||||
Makefile.componentbuild
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For components that e.g. include tools to generate source files from other files, it is necessary to be able to add recipes, macros or variable definitions
|
||||
into the component build process of every components. This is done by having a ``Makefile.componentbuild`` in a component directory. This file gets included
|
||||
in ``component_wrapper.mk``, before the ``component.mk`` of the component is included. As with the Makefile.projbuild, take care with these files: as they're
|
||||
included in each component build, a ``Makefile.componentbuild`` error may only show up when compiling an entirely different component.
|
||||
|
||||
Configuration-Only Components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@@ -20,8 +20,8 @@ found via http://www.freertos.org/a00106.html
|
||||
port of FreeRTOS v8.2.0, a number of FreeRTOS v9.0.0 features have been backported
|
||||
to ESP-IDF.
|
||||
|
||||
:ref:`tasks-and-task-creation`: Use ``xTaskCreatePinnedToCore()`` or
|
||||
``xTaskCreateStaticPinnedToCore()`` to create tasks in ESP-IDF FreeRTOS. The
|
||||
:ref:`tasks-and-task-creation`: Use :cpp:func:`xTaskCreatePinnedToCore` or
|
||||
:cpp:func:`xTaskCreateStaticPinnedToCore` to create tasks in ESP-IDF FreeRTOS. The
|
||||
last parameter of the two functions is ``xCoreID``. This parameter specifies
|
||||
which core the task is pinned to. Acceptable values are ``0`` for **PRO_CPU**,
|
||||
``1`` for **APP_CPU**, or ``tskNO_AFFINITY`` which allows the task to run on
|
||||
@@ -34,13 +34,13 @@ enter a blocked state, or are distributed across a wider range of priorities.
|
||||
|
||||
:ref:`scheduler-suspension`: Suspending the scheduler in ESP-IDF FreeRTOS will only
|
||||
affect the scheduler on the the calling core. In other words, calling
|
||||
``vTaskSuspendAll()`` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
|
||||
:cpp:func:`vTaskSuspendAll` on **PRO_CPU** will not prevent **APP_CPU** from scheduling, and
|
||||
vice versa. Use critical sections or semaphores instead for simultaneous
|
||||
access protection.
|
||||
|
||||
:ref:`tick-interrupt-synchronicity`: Tick interrupts of **PRO_CPU** and **APP_CPU**
|
||||
are not synchronized. Do not expect to use ``vTaskDelay`` or
|
||||
``vTaskDelayUntil`` as an accurate method of synchronizing task execution
|
||||
are not synchronized. Do not expect to use :cpp:func:`vTaskDelay` or
|
||||
:cpp:func:`vTaskDelayUntil` as an accurate method of synchronizing task execution
|
||||
between the two cores. Use a counting semaphore instead as their context
|
||||
switches are not tied to tick interrupts due to preemption.
|
||||
|
||||
@@ -50,12 +50,25 @@ scheduler and interrupts of the calling core. However the other core is left
|
||||
unaffected. If the other core attemps to take same mutex, it will spin until
|
||||
the calling core has released the mutex by exiting the critical section.
|
||||
|
||||
:ref:`deletion-callbacks`: ESP-IDF FreeRTOS has
|
||||
backported the Thread Local Storage Pointers feature. However they have the
|
||||
extra feature of deletion callbacks. Deletion callbacks are used to
|
||||
automatically free memory used by Thread Local Storage Pointers during the task
|
||||
deletion. Call ``vTaskSetThreadLocalStoragePointerAndDelCallback()``
|
||||
to set Thread Local Storage Pointers and deletion callbacks.
|
||||
:ref:`floating-points`: The ESP32 supports hardware acceleration of single
|
||||
precision floating point arithmetic (``float``). However the use of hardware
|
||||
acceleration leads to some behavioral restrictions in ESP-IDF FreeRTOS.
|
||||
Therefore, tasks that utilize ``float`` will automatically be pinned to a core if
|
||||
not done so already. Furthermore, ``float`` cannot be used in interrupt service
|
||||
routines.
|
||||
|
||||
:ref:`task-deletion`: Task deletion behavior has been backported from FreeRTOS
|
||||
v9.0.0 and modified to be SMP compatible. Task memory will be freed immediately
|
||||
when :cpp:func:`vTaskDelete` is called to delete a task that is not currently running
|
||||
and not pinned to the other core. Otherwise, freeing of task memory will still
|
||||
be delegated to the Idle Task.
|
||||
|
||||
:ref:`deletion-callbacks`: ESP-IDF FreeRTOS has backported the Thread Local
|
||||
Storage Pointers (TLSP) feature. However the extra feature of Deletion Callbacks has been
|
||||
added. Deletion callbacks are called automatically during task deletion and are
|
||||
used to free memory pointed to by TLSP. Call
|
||||
:cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback()` to set TLSP and Deletion
|
||||
Callbacks.
|
||||
|
||||
:ref:`FreeRTOS Hooks<hooks_api_reference>`: Vanilla FreeRTOS Hooks were not designed for SMP.
|
||||
ESP-IDF provides its own Idle and Tick Hooks in addition to the Vanilla FreeRTOS
|
||||
@@ -81,34 +94,34 @@ This feature has been backported from FreeRTOS v9.0.0 to ESP-IDF. The
|
||||
in order for static allocation functions to be available. Once enabled, the
|
||||
following functions can be called...
|
||||
|
||||
- ``xTaskCreateStatic()`` See :ref:`backporting-notes` below
|
||||
- ``xQueueCreateStatic()``
|
||||
- ``xSemaphoreCreateBinaryStatic()``
|
||||
- ``xSemaphoreCreateCountingStatic()``
|
||||
- ``xSemaphoreCreateMutexStatic()``
|
||||
- ``xSemaphoreCreateRecursiveMutexStatic()``
|
||||
- ``xTimerCreateStatic()`` See :ref:`backporting-notes` below
|
||||
- ``xEventGroupCreateStatic()``
|
||||
- :cpp:func:`xTaskCreateStatic` (see :ref:`backporting-notes` below)
|
||||
- :c:macro:`xQueueCreateStatic`
|
||||
- :c:macro:`xSemaphoreCreateBinaryStatic`
|
||||
- :c:macro:`xSemaphoreCreateCountingStatic`
|
||||
- :c:macro:`xSemaphoreCreateMutexStatic`
|
||||
- :c:macro:`xSemaphoreCreateRecursiveMutexStatic`
|
||||
- :cpp:func:`xTimerCreateStatic` (see :ref:`backporting-notes` below)
|
||||
- :cpp:func:`xEventGroupCreateStatic`
|
||||
|
||||
Other Features
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- ``vTaskSetThreadLocalStoragePointer()`` See :ref:`backporting-notes` below
|
||||
- ``pvTaskGetThreadLocalStoragePointer()`` See :ref:`backporting-notes` below
|
||||
- ``vTimerSetTimerID()``
|
||||
- ``xTimerGetPeriod()``
|
||||
- ``xTimerGetExpiryTime()``
|
||||
- ``pcQueueGetName()``
|
||||
- ``uxSemaphoreGetCount()``
|
||||
- :cpp:func:`vTaskSetThreadLocalStoragePointer` (see :ref:`backporting-notes` below)
|
||||
- :cpp:func:`pvTaskGetThreadLocalStoragePointer` (see :ref:`backporting-notes` below)
|
||||
- :cpp:func:`vTimerSetTimerID`
|
||||
- :cpp:func:`xTimerGetPeriod`
|
||||
- :cpp:func:`xTimerGetExpiryTime`
|
||||
- :cpp:func:`pcQueueGetName`
|
||||
- :c:macro:`uxSemaphoreGetCount`
|
||||
|
||||
.. _backporting-notes:
|
||||
|
||||
Backporting Notes
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
**1)** ``xTaskCreateStatic`` has been made SMP compatible in a similar
|
||||
fashion to ``xTaskCreate`` (see :ref:`tasks-and-task-creation`). Therefore
|
||||
``xTaskCreateStaticPinnedToCore()`` can also be called.
|
||||
**1)** :cpp:func:`xTaskCreateStatic` has been made SMP compatible in a similar
|
||||
fashion to :cpp:func:`xTaskCreate` (see :ref:`tasks-and-task-creation`). Therefore
|
||||
:cpp:func:`xTaskCreateStaticPinnedToCore` can also be called.
|
||||
|
||||
**2)** Although vanilla FreeRTOS allows the Timer feature's daemon task to
|
||||
be statically allocated, the daemon task is always dynamically allocated in
|
||||
@@ -117,7 +130,7 @@ defined when using statically allocated timers in ESP-IDF FreeRTOS.
|
||||
|
||||
**3)** The Thread Local Storage Pointer feature has been modified in ESP-IDF
|
||||
FreeRTOS to include Deletion Callbacks (see :ref:`deletion-callbacks`). Therefore
|
||||
the function ``vTaskSetThreadLocalStoragePointerAndDelCallback()`` can also be
|
||||
the function :cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback` can also be
|
||||
called.
|
||||
|
||||
|
||||
@@ -129,9 +142,9 @@ Tasks and Task Creation
|
||||
Tasks in ESP-IDF FreeRTOS are designed to run on a particular core, therefore
|
||||
two new task creation functions have been added to ESP-IDF FreeRTOS by
|
||||
appending ``PinnedToCore`` to the names of the task creation functions in
|
||||
vanilla FreeRTOS. The vanilla FreeRTOS functions of ``xTaskCreate()``
|
||||
and ``xTaskCreateStatic()`` have led to the addition of
|
||||
``xTaskCreatePinnedToCore()`` and ``xTaskCreateStaticPinnedToCore()`` in
|
||||
vanilla FreeRTOS. The vanilla FreeRTOS functions of :cpp:func:`xTaskCreate`
|
||||
and :cpp:func:`xTaskCreateStatic` have led to the addition of
|
||||
:cpp:func:`xTaskCreatePinnedToCore` and :cpp:func:`xTaskCreateStaticPinnedToCore` in
|
||||
ESP-IDF FreeRTOS (see :ref:`backported-features`).
|
||||
|
||||
For more details see :component_file:`freertos/task.c`
|
||||
@@ -151,9 +164,9 @@ of 1000 bytes. It should be noted that the ``uxStackDepth`` parameter in
|
||||
vanilla FreeRTOS specifies a task’s stack depth in terms of the number of
|
||||
words, whereas ESP-IDF FreeRTOS specifies the stack depth in terms of bytes.
|
||||
|
||||
Note that the vanilla FreeRTOS functions ``xTaskCreate`` and
|
||||
``xTaskCreateStatic`` have been macro defined in ESP-IDF FreeRTOS to call
|
||||
``xTaskCreatePinnedToCore()`` and ``xTaskCreateStaticPinnedToCore()``
|
||||
Note that the vanilla FreeRTOS functions :cpp:func:`xTaskCreate` and
|
||||
:cpp:func:`xTaskCreateStatic` have been defined in ESP-IDF FreeRTOS as inline functions which call
|
||||
:cpp:func:`xTaskCreatePinnedToCore` and :cpp:func:`xTaskCreateStaticPinnedToCore`
|
||||
respectively with ``tskNO_AFFINITY`` as the ``xCoreID`` value.
|
||||
|
||||
Each Task Control Block (TCB) in ESP-IDF stores the ``xCoreID`` as a member.
|
||||
@@ -270,18 +283,18 @@ different cores.
|
||||
Scheduler Suspension
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In vanilla FreeRTOS, suspending the scheduler via ``vTaskSuspendAll()`` will
|
||||
prevent calls of ``vTaskSwitchContext()`` from context switching until the
|
||||
scheduler has been resumed with ``vTaskResumeAll()``. However servicing ISRs
|
||||
In vanilla FreeRTOS, suspending the scheduler via :cpp:func:`vTaskSuspendAll` will
|
||||
prevent calls of ``vTaskSwitchContext`` from context switching until the
|
||||
scheduler has been resumed with :cpp:func:`xTaskResumeAll`. However servicing ISRs
|
||||
are still permitted. Therefore any changes in task states as a result from the
|
||||
current running task or ISRSs will not be executed until the scheduler is
|
||||
resumed. Scheduler suspension in vanilla FreeRTOS is a common protection method
|
||||
against simultaneous access of data shared between tasks, whilst still allowing
|
||||
ISRs to be serviced.
|
||||
|
||||
In ESP-IDF FreeRTOS, ``vTaskSuspendAll()`` will only prevent calls of
|
||||
In ESP-IDF FreeRTOS, :cpp:func:`xTaskResumeAll` will only prevent calls of
|
||||
``vTaskSwitchContext()`` from switching contexts on the core that called for the
|
||||
suspension. Hence if **PRO_CPU** calls ``vTaskSuspendAll()``, **APP_CPU** will
|
||||
suspension. Hence if **PRO_CPU** calls :cpp:func:`vTaskSuspendAll`, **APP_CPU** will
|
||||
still be able to switch contexts. If data is shared between tasks that are
|
||||
pinned to different cores, scheduler suspension is **NOT** a valid method of
|
||||
protection against simultaneous access. Consider using critical sections
|
||||
@@ -289,7 +302,7 @@ protection against simultaneous access. Consider using critical sections
|
||||
protecting shared resources in ESP-IDF FreeRTOS.
|
||||
|
||||
In general, it's better to use other RTOS primitives like mutex semaphores to protect
|
||||
against data shared between tasks, rather than ``vTaskSuspendAll()``.
|
||||
against data shared between tasks, rather than :cpp:func:`vTaskSuspendAll`.
|
||||
|
||||
|
||||
.. _tick-interrupt-synchronicity:
|
||||
@@ -303,8 +316,8 @@ each core being independent, and the tick interrupts to each core being
|
||||
unsynchronized.
|
||||
|
||||
In vanilla FreeRTOS the tick interrupt triggers a call to
|
||||
``xTaskIncrementTick()`` which is responsible for incrementing the tick
|
||||
counter, checking if tasks which have called ``vTaskDelay()`` have fulfilled
|
||||
:cpp:func:`xTaskIncrementTick` which is responsible for incrementing the tick
|
||||
counter, checking if tasks which have called :cpp:func:`vTaskDelay` have fulfilled
|
||||
their delay period, and moving those tasks from the Delayed Task List to the
|
||||
Ready Task List. The tick interrupt will then call the scheduler if a context
|
||||
switch is necessary.
|
||||
@@ -359,11 +372,11 @@ The ESP-IDF FreeRTOS critical section functions have been modified as follows…
|
||||
|
||||
- ``taskENTER_CRITICAL(mux)``, ``taskENTER_CRITICAL_ISR(mux)``,
|
||||
``portENTER_CRITICAL(mux)``, ``portENTER_CRITICAL_ISR(mux)`` are all macro
|
||||
defined to call ``vTaskEnterCritical()``
|
||||
defined to call :cpp:func:`vTaskEnterCritical`
|
||||
|
||||
- ``taskEXIT_CRITICAL(mux)``, ``taskEXIT_CRITICAL_ISR(mux)``,
|
||||
``portEXIT_CRITICAL(mux)``, ``portEXIT_CRITICAL_ISR(mux)`` are all macro
|
||||
defined to call ``vTaskExitCritical()``
|
||||
defined to call :cpp:func:`vTaskExitCritical`
|
||||
|
||||
For more details see :component_file:`freertos/include/freertos/portmacro.h`
|
||||
and :component_file:`freertos/task.c`
|
||||
@@ -375,41 +388,85 @@ mutex is provided upon entering and exiting, the type of call should not
|
||||
matter.
|
||||
|
||||
|
||||
.. _floating-points:
|
||||
|
||||
Floating Point Aritmetic
|
||||
------------------------
|
||||
|
||||
The ESP32 supports hardware acceleration of single precision floating point
|
||||
arithmetic (``float``) via Floating Point Units (FPU, also known as coprocessors)
|
||||
attached to each core. The use of the FPUs imposes some behavioral restrictions
|
||||
on ESP-IDF FreeRTOS.
|
||||
|
||||
ESP-IDF FreeRTOS implements Lazy Context Switching for FPUs. In other words,
|
||||
the state of a core's FPU registers are not immediately saved when a context
|
||||
switch occurs. Therefore, tasks that utilize ``float`` must be pinned to a
|
||||
particular core upon creation. If not, ESP-IDF FreeRTOS will automatically pin
|
||||
the task in question to whichever core the task was running on upon the task's
|
||||
first use of ``float``. Likewise due to Lazy Context Switching, interrupt service
|
||||
routines must also not use ``float``.
|
||||
|
||||
ESP32 does not support hardware acceleration for double precision floating point
|
||||
arithmetic (``double``). Instead ``double`` is implemented via software hence the
|
||||
behavioral restrictions with regards to ``float`` do not apply to ``double``. Note
|
||||
that due to the lack of hardware acceleration, ``double`` operations may consume
|
||||
significantly larger amount of CPU time in comparison to ``float``.
|
||||
|
||||
|
||||
.. _task-deletion:
|
||||
|
||||
Task Deletion
|
||||
-------------
|
||||
|
||||
FreeRTOS task deletion prior to v9.0.0 delegated the freeing of task memory
|
||||
entirely to the Idle Task. Currently, the freeing of task memory will occur
|
||||
immediately (within :cpp:func:`vTaskDelete`) if the task being deleted is not currently
|
||||
running or is not pinned to the other core (with respect to the core
|
||||
:cpp:func:`vTaskDelete` is called on). TLSP deletion callbacks will also run immediately
|
||||
if the same conditions are met.
|
||||
|
||||
However, calling :cpp:func:`vTaskDelete` to delete a task that is either currently
|
||||
running or pinned to the other core will still result in the freeing of memory
|
||||
being delegated to the Idle Task.
|
||||
|
||||
|
||||
.. _deletion-callbacks:
|
||||
|
||||
Thread Local Storage Pointers & Deletion Callbacks
|
||||
--------------------------------------------------
|
||||
|
||||
Thread Local Storage Pointers are pointers stored directly in the TCB which
|
||||
allows each task to have a pointer to a data structure containing that is
|
||||
specific to that task. However vanilla FreeRTOS provides no functionality to
|
||||
free the memory pointed to by the Thread Local Storage Pointers. Therefore if
|
||||
the memory pointed to by the Thread Local Storage Pointers is not explicitly
|
||||
freed by the user before a task is deleted, memory leak will occur.
|
||||
Thread Local Storage Pointers (TLSP) are pointers stored directly in the TCB.
|
||||
TLSP allow each task to have its own unique set of pointers to data structures.
|
||||
However task deletion behavior in vanilla FreeRTOS does not automatically
|
||||
free the memory pointed to by TLSP. Therefore if the memory pointed to by
|
||||
TLSP is not explicitly freed by the user before task deletion, memory leak will
|
||||
occur.
|
||||
|
||||
ESP-IDF FreeRTOS provides the added feature of deletion callbacks. These
|
||||
deletion callbacks are used to automatically free the memory pointed to by the
|
||||
Thread Local Storage Pointers when a task is deleted. Each Thread Local Storage
|
||||
Pointer can have its own call back, and these call backs are called when the
|
||||
Idle tasks cleans up a deleted tasks.
|
||||
ESP-IDF FreeRTOS provides the added feature of Deletion Callbacks. Deletion
|
||||
Callbacks are called automatically during task deletion to free memory pointed
|
||||
to by TLSP. Each TLSP can have its own Deletion Callback. Note that due to the
|
||||
to :ref:`task-deletion` behavior, there can be instances where Deletion
|
||||
Callbacks are called in the context of the Idle Tasks. Therefore Deletion
|
||||
Callbacks **should never attempt to block** and critical sections should be kept
|
||||
as short as possible to minimize priority inversion.
|
||||
|
||||
Vanilla FreeRTOS sets a Thread Local Storage Pointers using
|
||||
``vTaskSetThreadLocalStoragePointer()`` whereas ESP-IDF FreeRTOS sets a Thread
|
||||
Local Storage Pointers and Deletion Callbacks using
|
||||
``vTaskSetThreadLocalStoragePointerAndDelCallback()`` which accepts a pointer
|
||||
to the deletion call back as an extra parameter of type
|
||||
```TlsDeleteCallbackFunction_t``. Calling the vanilla FreeRTOS API
|
||||
``vTaskSetThreadLocalStoragePointer()`` is still valid however it is internally
|
||||
defined to call ``vTaskSetThreadLocalStoragePointerAndDelCallback()`` with a
|
||||
``NULL`` pointer as the deletion call back. This results in the selected Thread
|
||||
Local Storage Pointer to have no deletion call back.
|
||||
Deletion callbacks are of type
|
||||
``void (*TlsDeleteCallbackFunction_t)( int, void * )`` where the first parameter
|
||||
is the index number of the associated TLSP, and the second parameter is the
|
||||
TLSP itself.
|
||||
|
||||
In IDF the FreeRTOS thread local storage at index 0 is reserved and is used to implement
|
||||
the pthreads API thread local storage (pthread_getspecific() & pthread_setspecific()).
|
||||
Other indexes can be used for any purpose, provided
|
||||
:ref:`CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS` is set to a high enough value.
|
||||
Deletion callbacks are set alongside TLSP by calling
|
||||
:cpp:func:`vTaskSetThreadLocalStoragePointerAndDelCallback`. Calling the vanilla
|
||||
FreeRTOS function :cpp:func:`vTaskSetThreadLocalStoragePointer` will simply set the
|
||||
TLSP's associated Deletion Callback to `NULL` meaning that no callback will be
|
||||
called for that TLSP during task deletion. If a deletion callback is `NULL`,
|
||||
users should manually free the memory pointed to by the associated TLSP before
|
||||
task deletion in order to avoid memory leak.
|
||||
|
||||
For more details see :component_file:`freertos/include/freertos/task.h`
|
||||
:ref:`CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS` in menuconfig can be used
|
||||
to configure the number TLSP and Deletion Callbacks a TCB will have.
|
||||
|
||||
For more details see :doc:`FreeRTOS API reference<../api-reference/system/freertos>`.
|
||||
|
||||
|
||||
.. _esp-idf-freertos-configuration:
|
||||
@@ -434,7 +491,7 @@ number of Thread Local Storage Pointers each task will have in ESP-IDF
|
||||
FreeRTOS.
|
||||
|
||||
:ref:`CONFIG_SUPPORT_STATIC_ALLOCATION` will enable the backported
|
||||
functionality of ``xTaskCreateStaticPinnedToCore()`` in ESP-IDF FreeRTOS
|
||||
functionality of :cpp:func:`xTaskCreateStaticPinnedToCore` in ESP-IDF FreeRTOS
|
||||
|
||||
:ref:`CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION` will trigger a halt in
|
||||
particular functions in ESP-IDF FreeRTOS which have not been fully tested
|
||||
|
@@ -62,14 +62,32 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
ST R2, R1, 0 // write value of R2 into the third array element,
|
||||
// i.e. array[2]
|
||||
|
||||
Note about instruction execution time
|
||||
-------------------------------------
|
||||
|
||||
ULP coprocessor is clocked from RTC_FAST_CLK, which is normally derived from the internal 8MHz oscillator. Applications which need to know exact ULP clock frequency can calibrate it against the main XTAL clock::
|
||||
|
||||
#include "soc/rtc.h"
|
||||
|
||||
// calibrate 8M/256 clock against XTAL, get 8M/256 clock period
|
||||
uint32_t rtc_8md256_period = rtc_clk_cal(RTC_CAL_8MD256, 100);
|
||||
uint32_t rtc_fast_freq_hz = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / rtc_8md256_period;
|
||||
|
||||
ULP coprocessor needs 2 clock cycle to fetch each instuction (fetching is not pipelined), plus certain number of cycles to execute, depending on the instruction. See description of each instruction for details on the execution time.
|
||||
|
||||
Note that when accessing RTC memories and RTC registers, ULP coprocessor has lower priority than the main CPUs. This means that ULP coprocessor execution may be suspended while the main CPUs access same memory region as the ULP.
|
||||
|
||||
|
||||
**NOP** - no operation
|
||||
----------------------
|
||||
|
||||
**Syntax:**
|
||||
**Syntax**
|
||||
**NOP**
|
||||
**Operands:**
|
||||
**Operands**
|
||||
None
|
||||
**Description:**
|
||||
**Cycles**
|
||||
2 (fetch) + 1 (execute)
|
||||
**Description**
|
||||
No operation is performed. Only the PC is incremented.
|
||||
|
||||
**Example**::
|
||||
@@ -80,20 +98,22 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**ADD** - Add to register
|
||||
-------------------------
|
||||
|
||||
**Syntax:**
|
||||
**Syntax**
|
||||
**ADD** *Rdst, Rsrc1, Rsrc2*
|
||||
|
||||
**ADD** *Rdst, Rsrc1, imm*
|
||||
|
||||
|
||||
**Operands:**
|
||||
**Operands**
|
||||
- *Rdst* - Register R[0..3]
|
||||
- *Rsrc1* - Register R[0..3]
|
||||
- *Rsrc2* - Register R[0..3]
|
||||
- *Imm* - 16-bit signed value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description:**
|
||||
**Description**
|
||||
The instruction adds source register to another source register or to a 16-bit signed value and stores result to the destination register.
|
||||
|
||||
**Examples**::
|
||||
@@ -115,21 +135,24 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**SUB** - Subtract from register
|
||||
--------------------------------
|
||||
|
||||
**Syntax:**
|
||||
**Syntax**
|
||||
**SUB** *Rdst, Rsrc1, Rsrc2*
|
||||
|
||||
**SUB** *Rdst, Rsrc1, imm*
|
||||
|
||||
**Operands:**
|
||||
**Operands**
|
||||
- *Rdst* - Register R[0..3]
|
||||
- *Rsrc1* - Register R[0..3]
|
||||
- *Rsrc2* - Register R[0..3]
|
||||
- *Imm* - 16-bit signed value
|
||||
|
||||
**Description:**
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction subtracts the source register from another source register or subtracts 16-bit signed value from a source register, and stores result to the destination register.
|
||||
|
||||
**Examples:**::
|
||||
**Examples**::
|
||||
|
||||
1: SUB R1, R2, R3 //R1 = R2 - R3
|
||||
|
||||
@@ -146,21 +169,24 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**AND** - Logical AND of two operands
|
||||
-------------------------------------
|
||||
|
||||
**Syntax:**
|
||||
**Syntax**
|
||||
**AND** *Rdst, Rsrc1, Rsrc2*
|
||||
|
||||
**AND** *Rdst, Rsrc1, imm*
|
||||
|
||||
**Operands:**
|
||||
**Operands**
|
||||
- *Rdst* - Register R[0..3]
|
||||
- *Rsrc1* - Register R[0..3]
|
||||
- *Rsrc2* - Register R[0..3]
|
||||
- *Imm* - 16-bit signed value
|
||||
|
||||
**Description:**
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction does logical AND of a source register and another source register or 16-bit signed value and stores result to the destination register.
|
||||
|
||||
**Example**::
|
||||
**Examples**::
|
||||
|
||||
1: AND R1, R2, R3 //R1 = R2 & R3
|
||||
|
||||
@@ -183,13 +209,15 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
**OR** *Rdst, Rsrc1, imm*
|
||||
|
||||
|
||||
**Operands**
|
||||
- *Rdst* - Register R[0..3]
|
||||
- *Rsrc1* - Register R[0..3]
|
||||
- *Rsrc2* - Register R[0..3]
|
||||
- *Imm* - 16-bit signed value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction does logical OR of a source register and another source register or 16-bit signed value and stores result to the destination register.
|
||||
|
||||
@@ -223,6 +251,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Rsrc2* - Register R[0..3]
|
||||
- *Imm* - 16-bit signed value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction does logical shift to left of source register to number of bits from another source register or 16-bit signed value and store result to the destination register.
|
||||
|
||||
@@ -255,6 +286,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
*Rsrc2* - Register R[0..3]
|
||||
*Imm* - 16-bit signed value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction does logical shift to right of source register to number of bits from another source register or 16-bit signed value and store result to the destination register.
|
||||
|
||||
@@ -286,6 +320,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Rsrc* – Register R[0..3]
|
||||
- *Imm* – 16-bit signed value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction move to destination register value from source register or 16-bit signed value.
|
||||
|
||||
@@ -318,6 +355,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Rdst* – Register R[0..3], address of the destination, in 32-bit words
|
||||
- *Offset* – 10-bit signed value, offset in bytes
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 4 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction stores the 16-bit value of Rsrc to the lower half-word of memory with address Rdst+offset. The upper half-word is written with the current program counter (PC), expressed in words, shifted left by 5 bits::
|
||||
|
||||
@@ -352,6 +392,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
*Offset* – 10-bit signed value, offset in bytes
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 4 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction loads lower 16-bit half-word from memory with address Rsrc+offset into the destination register Rdst::
|
||||
|
||||
@@ -395,6 +438,8 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- EQ – jump if last ALU operation result was zero
|
||||
- OV – jump if last ALU has set overflow flag
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction makes jump to the specified address. Jump can be either unconditional or based on an ALU flag.
|
||||
@@ -432,6 +477,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
- *LT* (less than) – jump if value in R0 < threshold
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction makes a jump to a relative address if condition is true. Condition is the result of comparison of R0 register value and the threshold value.
|
||||
|
||||
@@ -461,6 +509,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *LT* (less than) – jump if value in stage_cnt < threshold
|
||||
- *GT* (greater than) – jump if value in stage_cnt > threshold
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction makes a jump to a relative address if condition is true. Condition is the result of comparison of count register value and threshold value.
|
||||
|
||||
@@ -487,6 +538,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Description**
|
||||
The instruction sets the stage count register to 0
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Examples**::
|
||||
|
||||
1: STAGE_RST // Reset stage count register
|
||||
@@ -502,6 +556,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Operands**
|
||||
- *Value* – 8 bits value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction increments stage count register by given value.
|
||||
|
||||
@@ -525,6 +582,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Operands**
|
||||
- *Value* – 8 bits value
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction decrements stage count register by given value.
|
||||
|
||||
@@ -548,17 +608,21 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
**Operands**
|
||||
No operands
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction halt the processor to the power down mode
|
||||
The instruction halts the ULP coprocessor and restarts ULP wakeup timer, if it is enabled.
|
||||
|
||||
**Examples**::
|
||||
|
||||
1: HALT // Move chip to powerdown
|
||||
1: HALT // Halt the coprocessor
|
||||
|
||||
|
||||
|
||||
**WAKE** – wakeup the chip
|
||||
--------------------------
|
||||
**WAKE** – Wake up the chip
|
||||
---------------------------
|
||||
|
||||
**Syntax**
|
||||
**WAKE**
|
||||
@@ -566,6 +630,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Operands**
|
||||
No operands
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction sends an interrupt from ULP to RTC controller.
|
||||
|
||||
@@ -573,9 +640,15 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
- If the SoC is not in deep sleep mode, and ULP interrupt bit (RTC_CNTL_ULP_CP_INT_ENA) is set in RTC_CNTL_INT_ENA_REG register, RTC interrupt will be triggered.
|
||||
|
||||
Note that before using WAKE instruction, ULP program may needs to wait until RTC controller is ready to wake up the main CPU. This is indicated using RTC_CNTL_RDY_FOR_WAKEUP bit of RTC_CNTL_LOW_POWER_ST_REG register. If WAKE instruction is executed while RTC_CNTL_RDY_FOR_WAKEUP is zero, it has no effect (wake up does not occur).
|
||||
|
||||
**Examples**::
|
||||
|
||||
1: WAKE // Trigger wake up
|
||||
1: is_rdy_for_wakeup: // Read RTC_CNTL_RDY_FOR_WAKEUP bit
|
||||
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
|
||||
AND r0, r0, 1
|
||||
JUMP is_rdy_for_wakeup, eq // Retry until the bit is set
|
||||
WAKE // Trigger wake up
|
||||
REG_WR 0x006, 24, 24, 0 // Stop ULP timer (clear RTC_CNTL_ULP_CP_SLP_TIMER_EN)
|
||||
HALT // Stop the ULP program
|
||||
// After these instructions, SoC will wake up,
|
||||
@@ -592,6 +665,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Operands**
|
||||
- *sleep_reg* – 0..4, selects one of ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers.
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 2 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction selects which of the ``SENS_ULP_CP_SLEEP_CYCx_REG`` (x = 0..4) register values is to be used by the ULP wakeup timer as wakeup period. By default, the value from ``SENS_ULP_CP_SLEEP_CYC0_REG`` is used.
|
||||
|
||||
@@ -612,6 +688,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
**Operands**
|
||||
- *Cycles* – number of cycles for wait
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + *Cycles* (execute)
|
||||
|
||||
**Description**
|
||||
The instruction delays for given number of cycles.
|
||||
|
||||
@@ -635,6 +714,8 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Rdst* – Destination Register R[0..3], result will be stored to this register
|
||||
- *Wait_Delay* – number of cycles used to perform the measurement
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + *Wait_Delay* + 3 * TSENS_CLK
|
||||
|
||||
**Description**
|
||||
The instruction performs measurement using TSENS and stores the result into a general purpose register.
|
||||
@@ -660,6 +741,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Sar_sel* – Select ADC: 0 = SARADC1, 1 = SARADC2
|
||||
- *Mux* - selected PAD, SARADC Pad[Mux+1] is enabled
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 21 + max(1, SAR_AMP_WAIT1) + max(1, SAR_AMP_WAIT2) + max(1, SAR_AMP_WAIT3) + SARx_SAMPLE_CYCLE + SARx_SAMPLE_BIT
|
||||
|
||||
**Description**
|
||||
The instruction makes measurements from ADC.
|
||||
|
||||
@@ -667,6 +751,51 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
|
||||
1: ADC R1, 0, 1 // Measure value using ADC1 pad 2 and store result into R1
|
||||
|
||||
**I2C_RD** - read single byte from I2C slave
|
||||
----------------------------------------------
|
||||
|
||||
**Syntax**
|
||||
- **I2C_RD** *Sub_addr, High, Low, Slave_sel*
|
||||
|
||||
**Operands**
|
||||
- *Sub_addr* – Address within the I2C slave to read.
|
||||
- *High*, *Low* — Define range of bits to read. Bits outside of [High, Low] range are masked.
|
||||
- *Slave_sel* - Index of I2C slave address to use.
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + I2C communication time
|
||||
|
||||
**Description**
|
||||
``I2C_RD`` instruction reads one byte from I2C slave with index ``Slave_sel``. Slave address (in 7-bit format) has to be set in advance into `SENS_I2C_SLAVE_ADDRx` register field, where ``x == Slave_sel``.
|
||||
8 bits of read result is stored into `R0` register.
|
||||
|
||||
**Examples**::
|
||||
|
||||
1: I2C_RD 0x10, 7, 0, 0 // Read byte from sub-address 0x10 of slave with address set in SENS_I2C_SLAVE_ADDR0
|
||||
|
||||
|
||||
**I2C_WR** - write single byte to I2C slave
|
||||
----------------------------------------------
|
||||
|
||||
**Syntax**
|
||||
- **I2C_WR** *Sub_addr, Value, High, Low, Slave_sel*
|
||||
|
||||
**Operands**
|
||||
- *Sub_addr* – Address within the I2C slave to write.
|
||||
- *Value* – 8-bit value to be written.
|
||||
- *High*, *Low* — Define range of bits to write. Bits outside of [High, Low] range are masked.
|
||||
- *Slave_sel* - Index of I2C slave address to use.
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + I2C communication time
|
||||
|
||||
**Description**
|
||||
``I2C_WR`` instruction writes one byte to I2C slave with index ``Slave_sel``. Slave address (in 7-bit format) has to be set in advance into `SENS_I2C_SLAVE_ADDRx` register field, where ``x == Slave_sel``.
|
||||
|
||||
**Examples**::
|
||||
|
||||
1: I2C_WR 0x20, 0x33, 7, 0, 1 // Write byte 0x33 to sub-address 0x20 of slave with address set in SENS_I2C_SLAVE_ADDR1.
|
||||
|
||||
|
||||
**REG_RD** – read from peripheral register
|
||||
------------------------------------------
|
||||
@@ -679,6 +808,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *High* – High part of R0
|
||||
- *Low* – Low part of R0
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 6 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction reads up to 16 bits from a peripheral register into a general purpose register: ``R0 = REG[Addr][High:Low]``.
|
||||
|
||||
@@ -704,6 +836,9 @@ Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the fol
|
||||
- *Low* – Low part of R0
|
||||
- *Data* – value to write, 8 bits
|
||||
|
||||
**Cycles**
|
||||
2 (fetch) + 10 (execute)
|
||||
|
||||
**Description**
|
||||
The instruction writes up to 8 bits from a general purpose register into a peripheral register. ``REG[Addr][High:Low] = data``
|
||||
|
||||
|
@@ -34,11 +34,10 @@ Short example of I2S configuration:
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = 0,
|
||||
.apll_param = I2S_APLL_NONE
|
||||
.use_apll = 0
|
||||
};
|
||||
|
||||
static const i2s_pin_config_t pin_config = {
|
||||
@@ -71,9 +70,10 @@ Short example configuring I2S to use internal DAC for analog output::
|
||||
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64
|
||||
.dma_buf_len = 64,
|
||||
.use_apll = 0
|
||||
};
|
||||
|
||||
...
|
||||
|
@@ -1,15 +1,264 @@
|
||||
RMT
|
||||
========
|
||||
===
|
||||
|
||||
Overview
|
||||
--------
|
||||
The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate or receive many other types of signals.
|
||||
|
||||
The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate many other types of signals.
|
||||
The signal, which consists of a series of pulses, is generated by RMT's transmitter based on a list of values. The values define the pulse duration and a binary level, see below. The transmitter can also provide a carrier and modulate it with provided pulses.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
.. blockdiag::
|
||||
:scale: 100
|
||||
:caption: RMT Transmitter Overview
|
||||
:align: center
|
||||
|
||||
blockdiag rmt_tx {
|
||||
|
||||
node_width = 80;
|
||||
node_height = 60;
|
||||
default_group_color = lightgrey;
|
||||
|
||||
a -> b -> c -> d;
|
||||
e -> f -> g -- h;
|
||||
d -> o [label=GPIO];
|
||||
h -> d [folded];
|
||||
|
||||
a [style=none, width=100, label="{11,high,7,low},\n{5,high,5,low},\n..."]
|
||||
b [label="Waveform\nGenerator"]
|
||||
c [style=none, label="", background="_static/rmt-waveform.png"]
|
||||
d [shape=beginpoint, label="mod"]
|
||||
e [style=none, width=60, height=40, label="Carrier\nenable"]
|
||||
f [label="Carrier\nGenerator"]
|
||||
g [style=none, label="", background="_static/rmt-carrier.png"]
|
||||
h [shape=none]
|
||||
o [style=none, label="", background="_static/rmt-waveform-modulated.png"]
|
||||
|
||||
group {
|
||||
label = Input
|
||||
a,e;
|
||||
}
|
||||
group {
|
||||
label = "RMT Transmitter"
|
||||
b,f,c,g,d,h;
|
||||
}
|
||||
group {
|
||||
label = Output
|
||||
o;
|
||||
}
|
||||
}
|
||||
|
||||
The reverse operation is performed by the receiver, where a series of pulses is decoded into a list of values containing the pulse duration and binary level. A filter may be applied to remove high frequency noise from the input signal.
|
||||
|
||||
.. blockdiag::
|
||||
:scale: 90
|
||||
:caption: RMT Receiver Overview
|
||||
:align: center
|
||||
|
||||
blockdiag rmt_rx {
|
||||
|
||||
node_width = 80;
|
||||
node_height = 60;
|
||||
default_group_color = lightgrey;
|
||||
|
||||
a -> b [label=GPIO];
|
||||
b -> c -> d;
|
||||
e -- f;
|
||||
f -> b [folded];
|
||||
|
||||
a [style=none, label="", background="_static/rmt-waveform.png"]
|
||||
b [label=Filter]
|
||||
c [label="Edge\nDetect"]
|
||||
d [style=none, width=100, label="{11,high,7,low},\n{5,high,5,low},\n..."]
|
||||
e [style=none, width=60, height=40, label="Filter\nenable"]
|
||||
f [shape=none, label=""]
|
||||
|
||||
group {
|
||||
label = Input
|
||||
a,e;
|
||||
}
|
||||
group {
|
||||
label = "RMT Receiver"
|
||||
b,c;
|
||||
}
|
||||
group {
|
||||
label = Output
|
||||
d;
|
||||
}
|
||||
}
|
||||
|
||||
There couple of typical steps to setup and operate the RMT and they are discussed in the following sections:
|
||||
|
||||
1. `Configure Driver`_
|
||||
2. `Transmit Data`_ or `Receive Data`_
|
||||
3. `Change Operation Parameters`_
|
||||
4. `Use Interrupts`_
|
||||
|
||||
The RMT has eight channels numbered from zero to seven. Each channel is able to independently transmit or receive data. They are referred to using indexes defined in structure :cpp:type:`rmt_channel_t`.
|
||||
|
||||
|
||||
Configure Driver
|
||||
----------------
|
||||
|
||||
There are several parameters that define how particular channel operates. Most of these parameters are configured by setting specific members of :cpp:type:`rmt_config_t` structure. Some of the parameters are common to both transmit or receive mode, and some are mode specific. They are all discussed below.
|
||||
|
||||
|
||||
Common Parameters
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The **channel** to be configured, select one from the :cpp:type:`rmt_channel_t` enumerator.
|
||||
* The RMT **operation mode** - whether this channel is used to transmit or receive data, selected by setting a **rmt_mode** members to one of the values from :cpp:type:`rmt_mode_t`.
|
||||
* What is the **pin number** to transmit or receive RMT signals, selected by setting **gpio_num**.
|
||||
* How many **memory blocks** will be used by the channel, set with **mem_block_num**.
|
||||
* A **clock divider**, that will determine the range of pulse length generated by the RMT transmitter or discriminated by the receiver. Selected by setting **clk_div** to a value within [1 .. 255] range. The RMT source clock is typically APB CLK, 80Mhz by default.
|
||||
|
||||
.. note::
|
||||
|
||||
The period of a square wave after the clock divider is called a 'tick'. The length of the pulses generated by the RMT transmitter or discriminated by the receiver is configured in number of 'ticks'.
|
||||
|
||||
There are also couple of specific parameters that should be set up depending if selected channel is configured in `Transmit Mode`_ or `Receive Mode`_:
|
||||
|
||||
|
||||
Transmit Mode
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
When configuring channel in transmit mode, set **tx_config** and the following members of :cpp:type:`rmt_tx_config_t`:
|
||||
|
||||
* Transmit the currently configured data items in a loop - **loop_en**
|
||||
* Enable the RMT carrier signal - **carrier_en**
|
||||
* Frequency of the carrier in Hz - **carrier_freq_hz**
|
||||
* Duty cycle of the carrier signal in percent (%) - **carrier_duty_percent**
|
||||
* Level of the RMT output, when the carrier is applied - **carrier_level**
|
||||
* Enable the RMT output if idle - **idle_output_en**
|
||||
* Set the signal level on the RMT output if idle - **idle_level**
|
||||
|
||||
|
||||
Receive Mode
|
||||
^^^^^^^^^^^^
|
||||
|
||||
In receive mode, set **rx_config** and the following members of :cpp:type:`rmt_rx_config_t`:
|
||||
|
||||
* Enable a filter on the input of the RMT receiver - **filter_en**
|
||||
* A threshold of the filter, set in the number of ticks - **filter_ticks_thresh**. Pulses shorter than this setting will be filtered out. Note, that the range of entered tick values is [0..255].
|
||||
* A pulse length threshold that will turn the RMT receiver idle, set in number of ticks - **idle_threshold**. The receiver will ignore pulses longer than this setting.
|
||||
|
||||
|
||||
Finalize Configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once the :cpp:type:`rmt_config_t` structure is populated with parameters, it should be then invoked with :cpp:func:`rmt_config` to make the configuration effective.
|
||||
|
||||
The last configuration step is installation of the driver in memory by calling :cpp:func:`rmt_driver_install`. If :cpp:type:`rx_buf_size` parameter of this function is > 0, then a ring buffer for incoming data will be allocated. A default ISR handler will be installed, see a note in `Use Interrupts`_.
|
||||
|
||||
Now, depending on how the channel is configured, we are ready to either `Transmit Data`_ or `Receive Data`_. This is described in next two sections.
|
||||
|
||||
|
||||
Transmit Data
|
||||
-------------
|
||||
|
||||
Before being able to transmit some RMT pulses, we need to define the pulse pattern. The minimum pattern recognized by the RMT controller, later called an 'item', is provided in a structure :cpp:type:`rmt_item32_t`, see :component_file:`soc/esp32/include/soc/rmt_struct.h`. Each item consists of two pairs of two values. The first value in a pair describes the signal duration in ticks and is 15 bits long, the second provides the signal level (high or low) and is contained in a single bit. A block of couple of items and the structure of an item is presented below.
|
||||
|
||||
.. packetdiag::
|
||||
:caption: Structure of RMT items (L - signal level)
|
||||
:align: center
|
||||
|
||||
packetdiag rmt_items {
|
||||
colwidth = 32
|
||||
node_width = 10
|
||||
node_height = 24
|
||||
default_fontsize = 12
|
||||
|
||||
0-14: Period (15)
|
||||
15: L
|
||||
16-30: Period (15)
|
||||
31: L
|
||||
32-95: ... [colheight=2]
|
||||
96-110: Period (15)
|
||||
111: L
|
||||
112-126: Period (15)
|
||||
127: L
|
||||
}
|
||||
|
||||
For a simple example how to define a block of items see :example:`peripherals/rmt_tx`.
|
||||
|
||||
The items are provided to the RMT controller by calling function :cpp:func:`rmt_write_items`. This function also automatically triggers start of transmission. It may be called to wait for transmission completion or exit just after transmission start. In such case you can wait for the transmission end by calling :cpp:func:`rmt_wait_tx_done`. This function does not limit the number of data items to transmit. It is using an interrupt to successively copy the new data chunks to RMT's internal memory as previously provided data are sent out.
|
||||
|
||||
Another way to provide data for transmission is by calling :cpp:func:`rmt_fill_tx_items`. In this case transmission is not started automatically. To control the transmission process use :cpp:func:`rmt_tx_start` and :cpp:func:`rmt_tx_stop`. The number of items to sent is restricted by the size of memory blocks allocated in the RMT controller's internal memory, see :cpp:func:`rmt_set_mem_block_num`.
|
||||
|
||||
|
||||
Receive Data
|
||||
------------
|
||||
|
||||
Before starting the receiver we need some storage for incoming items. The RMT controller has 512 x 32-bits of internal RAM shared between all eight channels. In typical scenarios it is not enough as an ultimate storage for all incoming (and outgoing) items. Therefore this API supports retrieval of incoming items on the fly to save them in a ring buffer of a size defined by the user. The size is provided when calling :cpp:func:`rmt_driver_install` discussed above. To get a handle to this buffer call :cpp:func:`rmt_get_ringbuf_handle`.
|
||||
|
||||
With the above steps complete we can start the receiver by calling :cpp:func:`rmt_rx_start` and then move to checking what's inside the buffer. To do so, you can use common FreeRTOS functions that interact with the ring buffer. Please see an example how to do it in :example:`peripherals/rmt_nec_tx_rx`.
|
||||
|
||||
To stop the receiver, call :cpp:func:`rmt_rx_stop`.
|
||||
|
||||
|
||||
Change Operation Parameters
|
||||
---------------------------
|
||||
|
||||
Previously described function :cpp:func:`rmt_config` provides a convenient way to set several configuration parameters in one shot. This is usually done on application start. Then, when the application is running, the API provides an alternate way to update individual parameters by calling dedicated functions. Each function refers to the specific RMT channel provided as the first input parameter. Most of the functions have `_get_` counterpart to read back the currently configured value.
|
||||
|
||||
|
||||
Parameters Common to Transmit and Receive Mode
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Selection of a GPIO pin number on the input or output of the RMT - :cpp:func:`rmt_set_pin`
|
||||
* Number of memory blocks allocated for the incoming or outgoing data - :cpp:func:`rmt_set_mem_pd`
|
||||
* Setting of the clock divider - :cpp:func:`rmt_set_clk_div`
|
||||
* Selection of the clock source, note that currently one clock source is supported, the APB clock which is 80Mhz - :cpp:func:`rmt_set_source_clk`
|
||||
|
||||
|
||||
Transmit Mode Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Enable or disable the loop back mode for the transmitter - :cpp:func:`rmt_set_tx_loop_mode`
|
||||
* Binary level on the output to apply the carrier - :cpp:func:`rmt_set_tx_carrier`, selected from :cpp:type:`rmt_carrier_level_t`
|
||||
* Determines the binary level on the output when transmitter is idle - :cpp:func:`rmt_set_idle_level()`, selected from :cpp:type:`rmt_idle_level_t`
|
||||
|
||||
|
||||
Receive Mode Parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The filter setting - :cpp:func:`rmt_set_rx_filter`
|
||||
* The receiver threshold setting - :cpp:func:`rmt_set_rx_idle_thresh`
|
||||
* Whether the transmitter or receiver is entitled to access RMT's memory - :cpp:func:`rmt_set_memory_owner`, selection is from :cpp:type:`rmt_mem_owner_t`.
|
||||
|
||||
|
||||
Use Interrupts
|
||||
--------------
|
||||
|
||||
Registering of an interrupt handler for the RMT controller is done be calling :cpp:func:`rmt_isr_register`.
|
||||
|
||||
.. note::
|
||||
|
||||
When calling :cpp:func:`rmt_driver_install` to use the system RMT driver, a default ISR is being installed. In such a case you cannot register a generic ISR handler with :cpp:func:`rmt_isr_register`.
|
||||
|
||||
The RMT controller triggers interrupts on four specific events describes below. To enable interrupts on these events, the following functions are provided:
|
||||
|
||||
* The RMT receiver has finished receiving a signal - :cpp:func:`rmt_set_rx_intr_en`
|
||||
* The RMT transmitter has finished transmitting the signal - :cpp:func:`rmt_set_tx_intr_en`
|
||||
* The number of events the transmitter has sent matches a threshold value :cpp:func:`rmt_set_tx_thr_intr_en`
|
||||
* Ownership to the RMT memory block has been violated - :cpp:func:`rmt_set_err_intr_en`
|
||||
|
||||
Setting or clearing an interrupt enable mask for specific channels and events may be also done by calling :cpp:func:`rmt_set_intr_enable_mask` or :cpp:func:`rmt_clr_intr_enable_mask`.
|
||||
|
||||
When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set specific bits described as ``RMT.int_clr.val.chN_event_name`` and defined as a ``volatile struct`` in :component_file:`soc/esp32/include/soc/rmt_struct.h`, where N is the RMT channel number [0, 7] and the ``event_name`` is one of four events described above.
|
||||
|
||||
If you do not need an ISR anymore, you can deregister it by calling a function :cpp:func:`rmt_isr_deregister`.
|
||||
|
||||
|
||||
Uninstall Driver
|
||||
----------------
|
||||
|
||||
If the RMT driver has been installed with :cpp:func:`rmt_driver_install` for some specific period of time and then not required, the driver may be removed to free allocated resources by calling :cpp:func:`rmt_driver_uninstall`.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
* A simple RMT TX example: :example:`peripherals/rmt_tx`.
|
||||
* NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`.
|
||||
|
||||
NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`.
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
42
docs/api-reference/system/freertos.rst
Normal file
42
docs/api-reference/system/freertos.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
FreeRTOS
|
||||
========
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This section contains documentation of FreeRTOS types, functions, and macros. It is automatically generated from FreeRTOS header files.
|
||||
|
||||
For more information about FreeRTOS features specific to ESP-IDF, see :doc:`ESP-IDF FreeRTOS SMP Changes<../../api-guides/freertos-smp>`.
|
||||
|
||||
|
||||
Task API
|
||||
--------
|
||||
|
||||
.. include:: /_build/inc/task.inc
|
||||
|
||||
Queue API
|
||||
---------
|
||||
|
||||
.. include:: /_build/inc/queue.inc
|
||||
|
||||
Semaphore API
|
||||
-------------
|
||||
|
||||
.. include:: /_build/inc/semphr.inc
|
||||
|
||||
Timer API
|
||||
---------
|
||||
|
||||
.. include:: /_build/inc/timers.inc
|
||||
|
||||
|
||||
Event Group API
|
||||
---------------
|
||||
|
||||
.. include:: /_build/inc/event_groups.inc
|
||||
|
||||
Ringbuffer API
|
||||
--------------
|
||||
|
||||
.. include:: /_build/inc/ringbuf.inc
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.. _hooks_api_reference:
|
||||
|
||||
ESP-IDF FreeRTOS Hooks
|
||||
======================
|
||||
FreeRTOS Hooks
|
||||
==============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
@@ -4,19 +4,20 @@ System API
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
FreeRTOS <freertos>
|
||||
FreeRTOS Hooks <hooks>
|
||||
Heap Memory Allocation <mem_alloc>
|
||||
Heap Memory Debugging <heap_debug>
|
||||
Interrupt Allocation <intr_alloc>
|
||||
Watchdogs <wdts>
|
||||
Hooks <hooks>
|
||||
Inter-Processor Call <ipc>
|
||||
High Resolution Timer <esp_timer>
|
||||
Over The Air Updates (OTA) <ota>
|
||||
Sleep Modes <sleep_modes>
|
||||
Power Management <power_management>
|
||||
Logging <log>
|
||||
Base MAC address <base_mac_address>
|
||||
Application Level Tracing <app_trace>
|
||||
Power Management <power_management>
|
||||
Sleep Modes <sleep_modes>
|
||||
Base MAC address <base_mac_address>
|
||||
Over The Air Updates (OTA) <ota>
|
||||
|
||||
|
||||
Example code for this API section is provided in :example:`system` directory of ESP-IDF examples.
|
||||
|
@@ -155,6 +155,7 @@ The following roles are provided:
|
||||
|
||||
A check is added to the CI build script, which searches RST files for presence of hard-coded links (identified by tree/master, blob/master, or raw/master part of the URL). This check can be run manually: ``cd docs`` and then ``make gh-linkcheck``.
|
||||
|
||||
.. _add-illustrations:
|
||||
|
||||
Add Illustrations
|
||||
-----------------
|
||||
@@ -172,7 +173,7 @@ The following types of diagrams are supported:
|
||||
|
||||
With this suite of tools it is possible to generate beautiful diagram images from simple text format (similar to graphviz’s DOT format). The diagram elements are laid out automatically. The diagram code is then converted into ".png" graphics and integrated "behind the scenes" into **Sphinx** documents.
|
||||
|
||||
For the diagram preparation you can use an on-line `interactive shell <http://interactive.blockdiag.com/?compression=deflate&src=eJxlUMFOwzAMvecrrO3aITYQQirlAIIzEseJQ5q4TUSIq8TVGIh_J2m7jbKc7Ge_5_dSO1Lv2soWvoVYgieNoMh7VGzJR9FJtugZ7lYQ0UcKEbYNOY36rRQHZHUPT68vV5tceGLbWCUzPfeaFFMoBZzecVc56vWwJFnWMmJ59CCZg617xpOFbTSyw0pmvT_HJ7hxtFNGBr6wvuu5SCkchcrZ1vAeXZomznh5YgTqfcpR02cBO6vZVDeXBRjMjKEcFRbLh8f18-Z2UUBDnqP9wmp9ncRmSSfND2ldGo2h_zse407g0Mxc1q7HzJ3-4jzYYTJjtQH3iSV-fgFzx50J>`_ that instantly shows the rendered image.
|
||||
For the diagram preparation you can use an on-line `interactive shell`_ that instantly shows the rendered image.
|
||||
|
||||
Below are couple of diagram examples:
|
||||
|
||||
@@ -185,7 +186,7 @@ Try them out by modifying the source code and see the diagram instantly renderin
|
||||
|
||||
.. note::
|
||||
|
||||
There may be slight differences in rendering of font used by the interactive shell compared to the font used in the esp-idf documentation.
|
||||
There may be slight differences in rendering of font used by the `interactive shell`_ compared to the font used in the esp-idf documentation.
|
||||
|
||||
|
||||
Put it all together
|
||||
@@ -207,7 +208,7 @@ OK, but I am new to Sphinx!
|
||||
|
||||
* Set up an account on `Read the Docs <https://readthedocs.org/>`_ and build documentation in the cloud. Read the Docs provides document building and hosting for free and their service works really quick and great.
|
||||
|
||||
4. To preview documentation before building use `Sublime Text <https://www.sublimetext.com/>`_ editor together with `OmniMarkupPreviewer <https://github.com/timonwong/OmniMarkupPreviewer>`_ plugin.
|
||||
4. To preview documentation before building, use `Sublime Text <https://www.sublimetext.com/>`_ editor together with `OmniMarkupPreviewer <https://github.com/timonwong/OmniMarkupPreviewer>`_ plugin.
|
||||
|
||||
|
||||
Setup for building documentation locally
|
||||
@@ -245,6 +246,28 @@ Installation of Doxygen is OS dependent:
|
||||
|
||||
brew install doxygen
|
||||
|
||||
.. note::
|
||||
|
||||
If you are installing on Windows system (Linux and MacOS users should skip this note), **before** going further, execute two extra steps below. These steps are required for the :ref:`blockdiag <add-illustrations>` to install:
|
||||
|
||||
1. Update all the system packages:
|
||||
|
||||
::
|
||||
|
||||
$ pacman -Syu
|
||||
|
||||
This process will likely require restarting of the MSYS2 MINGW32 console and repeating above commands, until update is complete.
|
||||
|
||||
2. Install *pillow*, that is one of dependences of the *blockdiag*:
|
||||
|
||||
::
|
||||
|
||||
$ pacman -S mingw32/mingw-w64-i686-python2-pillow
|
||||
|
||||
Check the log on the screen that ``mingw-w64-i686-python2-pillow-4.3.0-1`` is installed. Previous versions of *pillow* will not work.
|
||||
|
||||
A downside of Windows installation is that fonts of the `blockdiag pictures <add-illustrations>` do not render correctly, you will see some random characters instead. Until this issue is fixed, you can use the `interactive shell`_ to see how the complete picture looks like.
|
||||
|
||||
All remaining applications are `Python <https://www.python.org/>`_ packages and you can install them in one step as follows:
|
||||
|
||||
::
|
||||
@@ -279,3 +302,6 @@ Related Documents
|
||||
|
||||
|
||||
.. _espressif/esp-idf: https://github.com/espressif/esp-idf/
|
||||
|
||||
.. _interactive shell: http://interactive.blockdiag.com/?compression=deflate&src=eJxlUMFOwzAMvecrrO3aITYQQirlAIIzEseJQ5q4TUSIq8TVGIh_J2m7jbKc7Ge_5_dSO1Lv2soWvoVYgieNoMh7VGzJR9FJtugZ7lYQ0UcKEbYNOY36rRQHZHUPT68vV5tceGLbWCUzPfeaFFMoBZzecVc56vWwJFnWMmJ59CCZg617xpOFbTSyw0pmvT_HJ7hxtFNGBr6wvuu5SCkchcrZ1vAeXZomznh5YgTqfcpR02cBO6vZVDeXBRjMjKEcFRbLh8f18-Z2UUBDnqP9wmp9ncRmSSfND2ldGo2h_zse407g0Mxc1q7HzJ3-4jzYYTJjtQH3iSV-fgFzx50J
|
||||
|
||||
|
@@ -169,6 +169,15 @@ To re-format a file, run::
|
||||
|
||||
tools/format.sh components/my_component/file.c
|
||||
|
||||
|
||||
Configuring the code style for a project using EditorConfig
|
||||
-----------------------------------------------------------
|
||||
|
||||
EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. The EditorConfig project consists of a file format for defining coding styles and a collection of text editor plugins that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable and they work nicely with version control systems.
|
||||
|
||||
For more information, see `EditorConfig <http://editorconfig.org>`_ Website.
|
||||
|
||||
|
||||
Documenting code
|
||||
----------------
|
||||
|
||||
|
@@ -89,6 +89,22 @@ Quick Reset
|
||||
The keyboard shortcut ``Ctrl-T Ctrl-R`` will reset the target board via the RTS line (if it is connected.)
|
||||
|
||||
|
||||
Pause the Application
|
||||
=====================
|
||||
|
||||
The keyboard shortcut ``Ctrl-T Ctrl-P`` will reset the target into bootloader, so that the board will run nothing. This is
|
||||
useful when you want to wait for another device to startup. Then shortcut ``Ctrl-T Ctrl-R`` can be used to restart the
|
||||
application.
|
||||
|
||||
|
||||
Toggle Output Display
|
||||
=====================
|
||||
|
||||
Sometimes you may want to stop new output printed to screen, to see the log before. The keyboard shortcut ``Ctrl-T Ctrl-Y`` will
|
||||
toggle the display (discard all serial data when the display is off) so that you can stop to see the log, and revert
|
||||
again quickly without quitting the monitor.
|
||||
|
||||
|
||||
Simple Monitor
|
||||
==============
|
||||
|
||||
|
@@ -127,10 +127,6 @@ ESP-IDF will be downloaded into ``~/esp/esp-idf``.
|
||||
cd ~/esp/esp-idf
|
||||
git submodule update --init
|
||||
|
||||
.. note::
|
||||
|
||||
While cloning submodules on **Windows** platform, the ``git clone`` command may print some output starting ``': not a valid identifier...``. This is a `known issue <https://github.com/espressif/esp-idf/issues/11>`_ but the git clone still succeeds without any problems.
|
||||
|
||||
|
||||
.. _get-started-setup-path:
|
||||
|
||||
@@ -206,9 +202,6 @@ Here are couple of tips on navigation and use of ``menuconfig``:
|
||||
|
||||
If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``.
|
||||
|
||||
.. note::
|
||||
|
||||
Most ESP32 development boards have a 40MHz crystal installed. However, some boards use a 26MHz crystal. If your board uses a 26MHz crystal, or you get garbage output from serial port after code upload, adjust the :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` option in menuconfig.
|
||||
|
||||
.. _get-started-build-flash:
|
||||
|
||||
@@ -283,7 +276,18 @@ Several lines below, after start up and diagnostic log, you should see "Hello wo
|
||||
Restarting in 8 seconds...
|
||||
Restarting in 7 seconds...
|
||||
|
||||
To exit monitor use shortcut ``Ctrl+]``. To execute ``make flash`` and ``make monitor`` in one shoot type ``make flash monitor``. Check section :doc:`IDF Monitor <idf-monitor>` for handy shortcuts and more details on using this application.
|
||||
To exit the monitor use shortcut ``Ctrl+]``.
|
||||
|
||||
.. note::
|
||||
|
||||
If instead of the messages above, you see a random garbage similar to::
|
||||
|
||||
e<EFBFBD><EFBFBD><EFBFBD>)(Xn@<40>y.!<21><>(<28>PW+)<29><>Hn9a/9<>!<21>t5<74><35>P<EFBFBD>~<7E>k<EFBFBD><6B>e<EFBFBD>ea<65>5<EFBFBD>jA
|
||||
~zY<7A><59>Y(1<>,1<15><> e<><65><EFBFBD>)(Xn@<40>y.!Dr<44>zY(<28>jpi<70>|<7C>+z5Ymvp
|
||||
|
||||
or monitor fails shortly after upload, your board is likely using 26MHz crystal, while the ESP-IDF assumes default of 40MHz. Exit the monitor, go back to the :ref:`menuconfig <get-started-configure>`, change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz, then :ref:`build and flash <get-started-build-flash>` the application again.
|
||||
|
||||
To execute ``make flash`` and ``make monitor`` in one go, type ``make flash monitor``. Check section :doc:`IDF Monitor <idf-monitor>` for handy shortcuts and more details on using this application.
|
||||
|
||||
That's all what you need to get started with ESP32!
|
||||
|
||||
|
@@ -12,3 +12,4 @@ ESP32 Hardware Reference
|
||||
Modules and Boards <modules-and-boards>
|
||||
Previous Versions of Modules and Boards <modules-and-boards-previous>
|
||||
Espressif Products Ordering Information (PDF) <http://www.espressif.com/sites/default/files/documentation/espressif_products_ordering_information_en.pdf>
|
||||
Regulatory Certificates <http://espressif.com/en/certificates?field_product_value%5B%5D=ESP32&field_product_value%5B%5D=ESP-WROOM-32&field_product_value%5B%5D=ESP32-WROVER>
|
||||
|
@@ -1,7 +1,8 @@
|
||||
.. _esp-modules-and-boards:
|
||||
|
||||
************************
|
||||
ESP32 Modules and Boards
|
||||
========================
|
||||
************************
|
||||
|
||||
Espressif designed and manufactured several development modules and boards to help users evaluate functionality of the ESP32 family of chips. Development boards, depending on intended functionality, have exposed GPIO pins headers, provide USB programming interface, JTAG interface as well as peripherals like touch pads, LCD screen, SD card slot, camera module header, etc.
|
||||
|
||||
@@ -12,12 +13,34 @@ For details please refer to documentation below, provided together with descript
|
||||
This section describes the latest versions of boards. Previous versions of boards, including these not produced anymore, are described in section :ref:`esp-modules-and-boards-previous`.
|
||||
|
||||
|
||||
WROOM and WROVER Modules
|
||||
========================
|
||||
|
||||
A family of small modules that contain ESP32 chip on board together with some key components including a crystal oscillator and an antenna matching circuit. This makes it easier to provide an ESP32 based solution ready to integrate into final products. Such modules can be also used for evaluation after adding a few extra components like a programming interface, bootstrapping resistors and break out headers. The key characteristics of these modules are summarized in the following table. Some additional details are covered in the following chapters.
|
||||
|
||||
=============== ============ ===== ==== ==== ==== ==== ====
|
||||
-- Key Components Dimensions [mm]
|
||||
--------------- ------------------------------- ----------------
|
||||
Module Chip Flash RAM Ant. L W D
|
||||
=============== ============ ===== ==== ==== ==== ==== ====
|
||||
ESP-WROOM-32 ESP32-D0WDQ6 4MB -- MIFA 25.5 18 3.1
|
||||
ESP-WROOM-32D ESP32-D0WD 4MB -- MIFA 25.5 18 3.1
|
||||
ESP32-WROOM-32U ESP32-D0WD 4MB -- U.FL 19.2 18 3.2
|
||||
ESP32-WROVER ESP32-D0WDQ6 4MB 4MB MIFA 31.4 18 3.2
|
||||
ESP32-WROVER-I ESP32-D0WDQ6 4MB 4MB U.FL 31.4 18 3.5
|
||||
=============== ============ ===== ==== ==== ==== ==== ====
|
||||
|
||||
* MIFA - Meandered Inverted-F Antenna
|
||||
* U.FL - U.FL / IPEX antenna connector
|
||||
* `ESP32 Chip Datasheet <https://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf>`__ (PDF)
|
||||
|
||||
|
||||
.. _esp-modules-and-boards-esp-wroom-32:
|
||||
|
||||
ESP-WROOM-32
|
||||
------------
|
||||
|
||||
The smallest module intended for installation in final products. Can be also used for evaluation after adding extra components like programming interface, boot strapping resistors and break out headers.
|
||||
A basic and commonly adopted ESP32 module with ESP32-D0WDQ6 chip on board. The first one of the WROOM / WROVER family released to the market.
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wroom-32.jpg
|
||||
:align: center
|
||||
@@ -26,17 +49,48 @@ The smallest module intended for installation in final products. Can be also use
|
||||
|
||||
ESP-WROOM-32 module (front and back)
|
||||
|
||||
Documentation
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* `ESP-WROOM-32 Schematic <https://dl.espressif.com/dl/schematics/ESP-WROOM-32-v3.2_sch.pdf>`__ (PDF)
|
||||
* `ESP-WROOM-32 Datasheet <https://espressif.com/sites/default/files/documentation/esp-wroom-32_datasheet_en.pdf>`__ (PDF)
|
||||
* `ESP32 Module Reference Design <https://espressif.com/sites/default/files/documentation/esp32_module_reference_design.zip>`_ (ZIP) containing OrCAD schematic, PCB layout, gerbers and BOM
|
||||
|
||||
|
||||
.. _esp-modules-and-boards-esp-wroom-32d-and-u:
|
||||
|
||||
ESP-WROOM-32D / ESP32-WROOM-32U
|
||||
-------------------------------
|
||||
|
||||
Both modules have ESP32-D0WD chip on board of a smaller footprint than ESP32-D0WDQ6 installed in :ref:`ESP-WROOM-32 <esp-modules-and-boards-esp-wroom-32>`. Version "D" has a MIFA antenna. Version "U" has just an U.FL / IPEX antenna connector. That makes it 6.3 mm shorter comparing to "D", and also the smallest representative of the whole WROOM / WROVER family of modules.
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wroom-32d-front-back.jpg
|
||||
:align: center
|
||||
:alt: ESP-WROOM-32D module (back and front)
|
||||
:width: 40%
|
||||
|
||||
ESP-WROOM-32D module (back and front)
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wroom-32u-front-back.jpg
|
||||
:align: center
|
||||
:alt: ESP32-WROOM-32U module (back and front)
|
||||
:width: 40%
|
||||
|
||||
ESP32-WROOM-32U module (back and front)
|
||||
|
||||
|
||||
Documentation
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* `ESP-WROOM-32D / ESP32-WROOM-32U Datasheet <http://espressif.com/sites/default/files/documentation/esp-wroom-32d_esp32-wroom-32u_datasheet_en.pdf>`__ (PDF)
|
||||
|
||||
|
||||
.. _esp-modules-and-boards-esp32-wrover:
|
||||
|
||||
ESP32-WROVER
|
||||
------------
|
||||
|
||||
A step upgrade of ESP-WROOM-32 described above with an additional 4 MB SPI PSRAM (Pseudo static RAM). Module is provided in two versions: 'ESP32-WROVER' with PCB antenna (shown below) and 'ESP32-WROVER-I' with an IPEX antenna.
|
||||
A step upgrade of :ref:`esp-modules-and-boards-esp-wroom-32` with an additional 4 MB SPI PSRAM (Pseudo static RAM). This module is provided in two versions: 'ESP32-WROVER' with PCB antenna (shown below) and 'ESP32-WROVER-I' with an U.FL / IPEX antenna connector. Because of additional components inside, this module is 5.9 mm longer than :ref:`esp-modules-and-boards-esp-wroom-32`.
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-wrover.jpg
|
||||
:align: center
|
||||
@@ -46,7 +100,7 @@ A step upgrade of ESP-WROOM-32 described above with an additional 4 MB SPI PSRAM
|
||||
ESP32-WROVER module (front and back)
|
||||
|
||||
Documentation
|
||||
"""""""""""""
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
* `ESP32-WROVER Datasheet <https://espressif.com/sites/default/files/documentation/esp32-wrover_datasheet_en.pdf>`__ (PDF)
|
||||
* `ESP-PSRAM32 Datasheet <https://espressif.com/sites/default/files/documentation/esp-psram32_datasheet_en.pdf>`__ (PDF)
|
||||
@@ -55,7 +109,7 @@ Documentation
|
||||
.. _esp-modules-and-boards-esp32-pico-pit-v4:
|
||||
|
||||
ESP32-PICO-KIT V4
|
||||
-----------------
|
||||
=================
|
||||
|
||||
The smallest ESP32 development board with all the components required to connect it directly to a PC USB port, and pin headers to plug into a mini breadboard. It is equipped with ESP32-PICO-D4 chip that integrates 4MB flash memory, a crystal oscillator, filter capacitors and RF matching circuit in one single package. As result the fully functional development board requires only a few external components that can easy fit on a 20 x 52 mm PCB including antenna, LDO, USB-UART bridge and two buttons to reset it and put into download mode.
|
||||
|
||||
@@ -70,14 +124,14 @@ Comparing to ESP32-PICO-KIT V3, this version has revised printout and reduced nu
|
||||
|
||||
|
||||
Documentation
|
||||
"""""""""""""
|
||||
-------------
|
||||
|
||||
* :doc:`../get-started/get-started-pico-kit`
|
||||
* `ESP32-PICO-KIT V4 Schematic <https://dl.espressif.com/dl/schematics/esp32-pico-kit-v4_schematic.pdf>`_ (PDF)
|
||||
* `ESP32-PICO-D4 Datasheet <http://espressif.com/sites/default/files/documentation/esp32-pico-d4_datasheet_en.pdf>`_ (PDF)
|
||||
|
||||
Previous Versions
|
||||
"""""""""""""""""
|
||||
-----------------
|
||||
|
||||
* :ref:`esp-modules-and-boards-esp32-pico-pit-v3`
|
||||
|
||||
@@ -85,9 +139,9 @@ Previous Versions
|
||||
.. _esp-modules-and-boards-esp32-devkitc:
|
||||
|
||||
ESP32 Core Board V2 / ESP32 DevKitC
|
||||
-----------------------------------
|
||||
===================================
|
||||
|
||||
Small and convenient development board with ESP-WROOM-32 module installed, break out pin headers and minimum additional components. Includes USB to serial programming interface, that also provides power supply for the board. Has press buttons to reset the board and put it in upload mode.
|
||||
Small and convenient development board with :ref:`esp-modules-and-boards-esp-wroom-32` module installed, break out pin headers and minimum additional components. Includes USB to serial programming interface, that also provides power supply for the board. Has pushbuttons to reset the board and put it in upload mode.
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp32-core-board-v2.png
|
||||
:align: center
|
||||
@@ -97,7 +151,7 @@ Small and convenient development board with ESP-WROOM-32 module installed, break
|
||||
ESP32 Core Board V2 / ESP32 DevKitC board
|
||||
|
||||
Documentation
|
||||
"""""""""""""
|
||||
-------------
|
||||
|
||||
* :doc:`../get-started/get-started-devkitc`
|
||||
* `ESP32 DevKitC Schematic <https://dl.espressif.com/dl/schematics/ESP32-Core-Board-V2_sch.pdf>`__ (PDF)
|
||||
@@ -108,13 +162,13 @@ Documentation
|
||||
.. _esp-modules-and-boards-esp-wrover-kit-v3:
|
||||
|
||||
ESP-WROVER-KIT V3
|
||||
-----------------
|
||||
=================
|
||||
|
||||
The ESP-WROVER-KIT V3 development board has dual port USB to serial converter for programming and JTAG interface for debugging. Power supply is provided by USB interface or from standard 5 mm power supply jack. Power supply selection is done with a jumper and may be put on/off with a separate switch. This board has MicroSD card slot, 3.2” SPI LCD screen and dedicated header to connect a camera. It provides RGB diode for diagnostics. Includes 32.768 kHz XTAL for internal RTC to operate it in low power modes.
|
||||
|
||||
As all previous version of ESP-WROVER-KIT boards, it is ready to accommodate an :ref:`esp-modules-and-boards-esp-wroom-32` or :ref:`esp-modules-and-boards-esp32-wrover` module.
|
||||
|
||||
This is the first release of ESP-WROVER-KIT shipped with ESP32-WROVER module installed by default. This release also introduced several design changes to conditioning and interlocking of signals to the bootstrapping pins. Also, a zero Ohm resistor (R166) has been added between WROVER/WROOM module and VDD33 net, which can be desoldered, or replaced with a shunt resistor, for current measurement. This is intended to facilitate power consumption analysis in various operation modes of ESP32. Refer to schematic - the changes are enclosed in green border.
|
||||
This is the first release of ESP-WROVER-KIT shipped with :ref:`esp-modules-and-boards-esp32-wrover` module installed by default. This release also introduced several design changes to conditioning and interlocking of signals to the bootstrapping pins. Also, a zero Ohm resistor (R166) has been added between WROVER/WROOM module and VDD33 net, which can be desoldered, or replaced with a shunt resistor, for current measurement. This is intended to facilitate power consumption analysis in various operation modes of ESP32. Refer to schematic - the changes are enclosed in green border.
|
||||
|
||||
.. figure:: https://dl.espressif.com/dl/schematics/pictures/esp-wrover-kit-v3.jpg
|
||||
:align: center
|
||||
@@ -123,10 +177,10 @@ This is the first release of ESP-WROVER-KIT shipped with ESP32-WROVER module ins
|
||||
|
||||
ESP-WROVER-KIT V3 board
|
||||
|
||||
The camera header has been changed from male back to female. The board soldermask is matte black. The board on picture above has ESP32-WROVER is installed.
|
||||
The camera header has been changed from male back to female. The board soldermask is matte black. The board on picture above has :ref:`esp-modules-and-boards-esp32-wrover` is installed.
|
||||
|
||||
Documentation
|
||||
"""""""""""""
|
||||
-------------
|
||||
|
||||
* :doc:`../get-started/get-started-wrover-kit`
|
||||
* `ESP-WROVER-KIT V3 Schematic <https://dl.espressif.com/dl/schematics/ESP-WROVER-KIT_SCH-3.pdf>`__ (PDF)
|
||||
@@ -134,14 +188,14 @@ Documentation
|
||||
* `FTDI Virtual COM Port Drivers`_
|
||||
|
||||
Previous Versions
|
||||
"""""""""""""""""
|
||||
-----------------
|
||||
|
||||
* :ref:`esp-modules-and-boards-esp-wrover-kit-v1`
|
||||
* :ref:`esp-modules-and-boards-esp-wrover-kit-v2`
|
||||
|
||||
|
||||
Related Documents
|
||||
-----------------
|
||||
=================
|
||||
|
||||
* :doc:`modules-and-boards-previous`
|
||||
|
||||
|
@@ -33,10 +33,10 @@
|
||||
|
||||
#define GPIO_OUTPUT_IO_0 18
|
||||
#define GPIO_OUTPUT_IO_1 19
|
||||
#define GPIO_OUTPUT_PIN_SEL ((1<<GPIO_OUTPUT_IO_0) | (1<<GPIO_OUTPUT_IO_1))
|
||||
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
|
||||
#define GPIO_INPUT_IO_0 4
|
||||
#define GPIO_INPUT_IO_1 5
|
||||
#define GPIO_INPUT_PIN_SEL ((1<<GPIO_INPUT_IO_0) | (1<<GPIO_INPUT_IO_1))
|
||||
#define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
|
||||
#define ESP_INTR_FLAG_DEFAULT 0
|
||||
|
||||
static xQueueHandle gpio_evt_queue = NULL;
|
||||
|
9
examples/peripherals/rmt_tx/Makefile
Normal file
9
examples/peripherals/rmt_tx/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := rmt_tx
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
25
examples/peripherals/rmt_tx/README.md
Normal file
25
examples/peripherals/rmt_tx/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# RMT Transmit Example
|
||||
|
||||
This example shows how to configure and operate the remote control (RMT) peripheral to transmit a sample message in the [Morse code](https://en.wikipedia.org/wiki/Morse_code).
|
||||
|
||||
Configuration (pin number, etc.) can be modified in the top of the `main/rmt_tx_main.c` file.
|
||||
|
||||
To be able to see and hear the message output by the RMT, connect a LED and a speaker or an earphone (be careful - it may be loud) to the GPIO configured under `RMT_TX_GPIO` define (default is GPIO 18).
|
||||
|
||||
Example connections:
|
||||
|
||||
```
|
||||
330R LED
|
||||
GPIO18 +----/\/\/\----+------|>|-----+ GND
|
||||
|
|
||||
| /|
|
||||
+-+ | Speaker
|
||||
| | | or
|
||||
+-+ | earphone
|
||||
| \|
|
||||
|
|
||||
+--------------+ GND
|
||||
```
|
||||
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
4
examples/peripherals/rmt_tx/main/component.mk
Normal file
4
examples/peripherals/rmt_tx/main/component.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
95
examples/peripherals/rmt_tx/main/rmt_tx_main.c
Normal file
95
examples/peripherals/rmt_tx/main/rmt_tx_main.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* RMT transmit example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt.h"
|
||||
|
||||
static const char *RMT_TX_TAG = "RMT Tx";
|
||||
|
||||
#define RMT_TX_CHANNEL RMT_CHANNEL_0
|
||||
#define RMT_TX_GPIO 18
|
||||
|
||||
/*
|
||||
* Prepare a raw table with a message in the Morse code
|
||||
*
|
||||
* The message is "ESP" : . ... .--.
|
||||
*
|
||||
* The table structure represents the RMT item structure:
|
||||
* {duration, level, duration, level}
|
||||
*
|
||||
*/
|
||||
rmt_item32_t items[] = {
|
||||
// E : dot
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
//
|
||||
{{{ 32767, 0, 32767, 0 }}}, // SPACE
|
||||
// S : dot, dot, dot
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
//
|
||||
{{{ 32767, 0, 32767, 0 }}}, // SPACE
|
||||
// P : dot, dash, dash, dot
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
{{{ 32767, 1, 32767, 1 }}},
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dash
|
||||
{{{ 32767, 1, 32767, 1 }}},
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dash
|
||||
{{{ 32767, 1, 32767, 0 }}}, // dot
|
||||
|
||||
// RMT end marker
|
||||
{{{ 0, 1, 0, 0 }}}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the RMT Tx channel
|
||||
*/
|
||||
static void rmt_tx_int()
|
||||
{
|
||||
rmt_config_t config;
|
||||
config.rmt_mode = RMT_MODE_TX;
|
||||
config.channel = RMT_TX_CHANNEL;
|
||||
config.gpio_num = RMT_TX_GPIO;
|
||||
config.mem_block_num = 1;
|
||||
config.tx_config.loop_en = 0;
|
||||
// enable the carrier to be able to hear the Morse sound
|
||||
// if the RMT_TX_GPIO is connected to a speaker
|
||||
config.tx_config.carrier_en = 1;
|
||||
config.tx_config.idle_output_en = 1;
|
||||
config.tx_config.idle_level = 0;
|
||||
config.tx_config.carrier_duty_percent = 50;
|
||||
// set audible career frequency of 611 Hz
|
||||
// actually 611 Hz is the minimum, that can be set
|
||||
// with current implementation of the RMT API
|
||||
config.tx_config.carrier_freq_hz = 611;
|
||||
config.tx_config.carrier_level = 1;
|
||||
// set the maximum clock divider to be able to output
|
||||
// RMT pulses in range of about one hundred milliseconds
|
||||
config.clk_div = 255;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&config));
|
||||
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
void app_main(void *ignore)
|
||||
{
|
||||
ESP_LOGI(RMT_TX_TAG, "Configuring transmitter");
|
||||
rmt_tx_int();
|
||||
int number_of_items = sizeof(items) / sizeof(items[0]);
|
||||
|
||||
while (1) {
|
||||
ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, items, number_of_items, true));
|
||||
ESP_LOGI(RMT_TX_TAG, "Transmission complete");
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
@@ -130,6 +130,11 @@ edge_detected:
|
||||
|
||||
.global wake_up
|
||||
wake_up:
|
||||
/* Check if the system can be woken up */
|
||||
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
|
||||
and r0, r0, 1
|
||||
jump wake_up, eq
|
||||
|
||||
/* Wake up the SoC, end program */
|
||||
wake
|
||||
halt
|
||||
|
@@ -105,7 +105,7 @@ exit:
|
||||
.global wake_up
|
||||
wake_up:
|
||||
/* Check if the system can be woken up */
|
||||
READ_RTC_REG(RTC_CNTL_DIAG0_REG, 19, 1)
|
||||
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
|
||||
and r0, r0, 1
|
||||
jump exit, eq
|
||||
|
||||
|
@@ -73,11 +73,36 @@ COMPONENT_SUBMODULES ?=
|
||||
|
||||
################################################################################
|
||||
# 2) Include the component.mk for the specific component (COMPONENT_MAKEFILE) to
|
||||
# override variables & optionally define custom targets.
|
||||
# override variables & optionally define custom targets. Also include global
|
||||
# component makefiles.
|
||||
################################################################################
|
||||
|
||||
|
||||
# Include any Makefile.componentbuild file letting components add
|
||||
# configuration at the global component level
|
||||
|
||||
# Save component_path; we pass it to the called Makefile.componentbuild
|
||||
# as COMPILING_COMPONENT_PATH, and we use it to restore the current
|
||||
# COMPONENT_PATH later.
|
||||
COMPILING_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
|
||||
define includeCompBuildMakefile
|
||||
$(if $(V),$(info including $(1)/Makefile.componentbuild...))
|
||||
COMPONENT_PATH := $(1)
|
||||
include $(1)/Makefile.componentbuild
|
||||
endef
|
||||
$(foreach componentpath,$(COMPONENT_PATHS), \
|
||||
$(if $(wildcard $(componentpath)/Makefile.componentbuild), \
|
||||
$(eval $(call includeCompBuildMakefile,$(componentpath)))))
|
||||
|
||||
#Restore COMPONENT_PATH to what it was
|
||||
COMPONENT_PATH := $(COMPILING_COMPONENT_PATH)
|
||||
|
||||
|
||||
# Include component.mk for this component.
|
||||
include $(COMPONENT_MAKEFILE)
|
||||
|
||||
|
||||
################################################################################
|
||||
# 3) Set variables that depend on values that may changed by component.mk
|
||||
################################################################################
|
||||
@@ -85,11 +110,12 @@ include $(COMPONENT_MAKEFILE)
|
||||
ifndef COMPONENT_CONFIG_ONLY # Skip steps 3-5 if COMPONENT_CONFIG_ONLY is set
|
||||
|
||||
# Object files which need to be linked into the library
|
||||
# By default we take all .c, .cpp & .S files in COMPONENT_SRCDIRS.
|
||||
# By default we take all .c, .cpp, .cc & .S files in COMPONENT_SRCDIRS.
|
||||
ifndef COMPONENT_OBJS
|
||||
# Find all source files in all COMPONENT_SRCDIRS
|
||||
COMPONENT_OBJS := $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.c,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.c)))
|
||||
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cpp,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cpp)))
|
||||
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.cc,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.cc)))
|
||||
COMPONENT_OBJS += $(foreach compsrcdir,$(COMPONENT_SRCDIRS),$(patsubst %.S,%.o,$(wildcard $(COMPONENT_PATH)/$(compsrcdir)/*.S)))
|
||||
# Make relative by removing COMPONENT_PATH from all found object paths
|
||||
COMPONENT_OBJS := $(patsubst $(COMPONENT_PATH)/%,%,$(COMPONENT_OBJS))
|
||||
@@ -221,6 +247,11 @@ $(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE
|
||||
$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
|
||||
$(call AppendSourceToDependencies,$$<,$$@)
|
||||
|
||||
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cc $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS)
|
||||
$$(summary) CXX $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@
|
||||
$$(CXX) $$(CXXFLAGS) $$(CPPFLAGS) $$(addprefix -I,$$(COMPONENT_INCLUDES)) $$(addprefix -I,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
|
||||
$(call AppendSourceToDependencies,$$<,$$@)
|
||||
|
||||
$(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(COMPONENT_SRCDIRS)
|
||||
$$(summary) AS $$(patsubst $$(PWD)/%,%,$$(CURDIR))/$$@
|
||||
$$(CC) $$(CPPFLAGS) $$(DEBUG_FLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@
|
||||
|
@@ -154,6 +154,7 @@ export COMPONENTS
|
||||
# NOTE: These paths must be generated WITHOUT a trailing / so we
|
||||
# can use $(notdir x) to get the component name.
|
||||
COMPONENT_PATHS := $(foreach comp,$(COMPONENTS),$(firstword $(foreach cd,$(COMPONENT_DIRS),$(wildcard $(dir $(cd))$(comp) $(cd)/$(comp)))))
|
||||
export COMPONENT_PATHS
|
||||
|
||||
TEST_COMPONENTS ?=
|
||||
TESTS_ALL ?=
|
||||
|
@@ -55,6 +55,8 @@ CTRL_F = '\x06'
|
||||
CTRL_H = '\x08'
|
||||
CTRL_R = '\x12'
|
||||
CTRL_T = '\x14'
|
||||
CTRL_Y = '\x19'
|
||||
CTRL_P = '\x10'
|
||||
CTRL_RBRACKET = '\x1d' # Ctrl+]
|
||||
|
||||
# ANSI terminal codes
|
||||
@@ -256,6 +258,7 @@ class Monitor(object):
|
||||
self._pressed_menu_key = False
|
||||
self._read_line = b""
|
||||
self._gdb_buffer = b""
|
||||
self._output_enabled = True
|
||||
|
||||
def main_loop(self):
|
||||
self.console_reader.start()
|
||||
@@ -299,6 +302,7 @@ class Monitor(object):
|
||||
# this may need to be made more efficient, as it pushes out a byte
|
||||
# at a time to the console
|
||||
for b in data:
|
||||
if self._output_enabled:
|
||||
self.console.write_bytes(b)
|
||||
if b == b'\n': # end of line
|
||||
self.handle_serial_input_line(self._read_line.strip())
|
||||
@@ -320,10 +324,23 @@ class Monitor(object):
|
||||
self.serial.setRTS(True)
|
||||
time.sleep(0.2)
|
||||
self.serial.setRTS(False)
|
||||
self.output_enable(True)
|
||||
elif c == CTRL_F: # Recompile & upload
|
||||
self.run_make("flash")
|
||||
elif c == CTRL_A: # Recompile & upload app only
|
||||
self.run_make("app-flash")
|
||||
elif c == CTRL_Y: # Toggle output display
|
||||
self.output_toggle()
|
||||
elif c == CTRL_P:
|
||||
yellow_print("Pause app (enter bootloader mode), press Ctrl-T Ctrl-R to restart")
|
||||
# to fast trigger pause without press menu key
|
||||
self.serial.setDTR(False) # IO0=HIGH
|
||||
self.serial.setRTS(True) # EN=LOW, chip in reset
|
||||
time.sleep(1.3) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.1
|
||||
self.serial.setDTR(True) # IO0=LOW
|
||||
self.serial.setRTS(False) # EN=HIGH, chip out of reset
|
||||
time.sleep(0.45) # timeouts taken from esptool.py, includes esp32r0 workaround. defaults: 0.05
|
||||
self.serial.setDTR(False) # IO0=HIGH, done
|
||||
else:
|
||||
red_print('--- unknown menu character {} --'.format(key_description(c)))
|
||||
|
||||
@@ -340,13 +357,16 @@ class Monitor(object):
|
||||
--- {reset:7} Reset target board via RTS line
|
||||
--- {make:7} Run 'make flash' to build & flash
|
||||
--- {appmake:7} Run 'make app-flash to build & flash app
|
||||
--- {output:7} Toggle output display
|
||||
--- {pause:7} Reset target into bootloader to pause app via RTS line
|
||||
""".format(version=__version__,
|
||||
exit=key_description(self.exit_key),
|
||||
menu=key_description(self.menu_key),
|
||||
reset=key_description(CTRL_R),
|
||||
make=key_description(CTRL_F),
|
||||
appmake=key_description(CTRL_A),
|
||||
|
||||
output=key_description(CTRL_Y),
|
||||
pause=key_description(CTRL_P),
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
@@ -393,6 +413,8 @@ class Monitor(object):
|
||||
p.wait()
|
||||
if p.returncode != 0:
|
||||
self.prompt_next_action("Build failed")
|
||||
else:
|
||||
self.output_enable(True)
|
||||
|
||||
def lookup_pc_address(self, pc_addr):
|
||||
translation = subprocess.check_output(
|
||||
@@ -430,6 +452,13 @@ class Monitor(object):
|
||||
pass # happens on Windows, maybe other OSes
|
||||
self.prompt_next_action("gdb exited")
|
||||
|
||||
def output_enable(self, enable):
|
||||
self._output_enabled = enable
|
||||
|
||||
def output_toggle(self):
|
||||
self._output_enabled = not self._output_enabled
|
||||
yellow_print("\nToggle output display: {}, Type Ctrl-T Ctrl-Y to show/disable output again.".format(self._output_enabled))
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser("idf_monitor - a serial output monitor for esp-idf")
|
||||
|
||||
|
@@ -23,6 +23,22 @@ CFLAGS :=
|
||||
CPPFLAGS :=
|
||||
LDFLAGS :=
|
||||
|
||||
# Workaround for a bug on Windows if the mingw32 host compilers
|
||||
# are installed in addition to the MSYS ones. The kconfig tools
|
||||
# need to be compiled using the MSYS compiler.
|
||||
#
|
||||
# See https://github.com/espressif/esp-idf/issues/1296
|
||||
ifdef MSYSTEM
|
||||
ifeq ("$(MSYSTEM)", "MINGW32")
|
||||
ifeq ("$(CC)", "cc")
|
||||
CC := /usr/bin/gcc
|
||||
endif
|
||||
ifeq ("$(LD)", "ld")
|
||||
LD := /usr/bin/ld
|
||||
endif
|
||||
endif # MING32
|
||||
endif # MSYSTEM
|
||||
|
||||
default: mconf conf
|
||||
|
||||
xconfig: qconf
|
||||
|
@@ -1,5 +1,5 @@
|
||||
%option nostdinit noyywrap never-interactive full ecs
|
||||
%option 8bit nodefault perf-report perf-report
|
||||
%option 8bit perf-report perf-report
|
||||
%option noinput
|
||||
%x COMMAND HELP STRING PARAM
|
||||
%{
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
void unityTask(void *pvParameters)
|
||||
{
|
||||
vTaskDelay(30); /* Delay a bit to let the main task be deleted */
|
||||
vTaskDelay(2); /* Delay a bit to let the main task be deleted */
|
||||
unity_run_menu(); /* Doesn't return */
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user