From 5275f29efe64210638c7f44f00dc747a92874efe Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 6 Mar 2017 21:44:10 +0100 Subject: [PATCH 01/57] doc: add dev module and boards by Espressif --- docs/index.rst | 1 + docs/modules-and-boards.rst | 77 +++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 docs/modules-and-boards.rst diff --git a/docs/index.rst b/docs/index.rst index 4beb32628..63e193d3e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -57,6 +57,7 @@ Contents: Pin List and Functions (PDF) Chip Pinout (PDF) Silicon Errata (PDF) + Modules and Boards .. toctree:: :caption: Contribute diff --git a/docs/modules-and-boards.rst b/docs/modules-and-boards.rst new file mode 100644 index 000000000..22307fd2b --- /dev/null +++ b/docs/modules-and-boards.rst @@ -0,0 +1,77 @@ +ESP32 Modules and Boards +======================== + +Espressif designed and manufactured several development modules and boards to help users evaluate functionality of ESP32 chip. 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. + +For details please refer to documentation below, provided together with description of particular boards. + + +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. + +.. image:: http://dl.espressif.com/dl/schematics/pictures/esp-wroom-32.jpg + :align: center + :width: 40% + :alt: ESP-WROOM-32 module (front and back) + +* `Schematic `__ (PDF) +* `ESP32 Module Reference Design `_ (ZIP) containing: OrCAD schematic, PCB layout, gerbers and BOM + + +ESP32 Core Board V2 / ESP32 DevKitC +----------------------------------- + +Small and convenient development module with break out pin headers and minimum additional components. Includes USB to serial programming interface that also provides power supply for the module. Has press buttons to reset the module and put it in upload mode. + +.. image:: http://dl.espressif.com/dl/schematics/pictures/esp32-core-board-v2.jpg + :align: center + :width: 50% + :alt: ESP32 Core Board V2 / ESP32 DevKitC board + +* `Schematic `__ (PDF) +* `ESP32 Development Board Reference Design `_ (ZIP) containing: OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32-DevKitC Getting Started Guide `_ (PDF) + + + +ESP32 Demo Board V2 +------------------- + +One of first feature rich evaluation boards that contains several pin headers, dip switches, USB to serial programming interface, reset and boot mode press buttons, power switch, 10 touch pads and separate header to connect LCD screen. + +.. image:: http://dl.espressif.com/dl/schematics/pictures/esp32-demo-board-v2.jpg + :align: center + :alt: ESP32 Demo Board V2 board + +* `Schematic `__ (PDF) + + +ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 +-------------------------------------- + +Development board that 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. Has SD card slot, 3.2” SPI LCD screen and dedicated header to connect a camera. Provides RGB diode for diagnostics. Also includes 32.768KHz XTAL for internal RTC to operate it in low power modes. + +.. image:: http://dl.espressif.com/dl/schematics/pictures/esp32-devkitj-v1.jpg + :align: center + :width: 90% + :alt: ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 board + +* `Schematic `__ (PDF) + + +ESP32 WROVER KIT V2 +------------------- + +This is an updated version of ESP32 DevKitJ V1 described above with design improvements identified when DevKitJ was in use. Both V1 and V2 versions of this board are ready to accommodate existing ESP-WROOM-32 or the new ESP32-WROVER module. + +.. image:: http://dl.espressif.com/dl/schematics/pictures/esp-wrover-kit-v2.jpg + :align: center + :width: 90% + :alt: ESP32 WROVER KIT V2 board + +* `Schematic `__ (PDF) +* `ESP-WROVER-KIT Getting Started Guide `_ (PDF) + + From 79449cce577fcb333569da0d7daf91a12cfaa95a Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Tue, 7 Mar 2017 20:20:02 +0100 Subject: [PATCH 02/57] ESP32 module datasheet and JTAG debugger App Note links --- docs/modules-and-boards.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/modules-and-boards.rst b/docs/modules-and-boards.rst index 22307fd2b..208ec442f 100644 --- a/docs/modules-and-boards.rst +++ b/docs/modules-and-boards.rst @@ -17,13 +17,14 @@ The smallest module intended for installation in final products. Can be also use :alt: ESP-WROOM-32 module (front and back) * `Schematic `__ (PDF) +* `Datasheet `__ (PDF) * `ESP32 Module Reference Design `_ (ZIP) containing: OrCAD schematic, PCB layout, gerbers and BOM ESP32 Core Board V2 / ESP32 DevKitC ----------------------------------- -Small and convenient development module with break out pin headers and minimum additional components. Includes USB to serial programming interface that also provides power supply for the module. Has press buttons to reset the module and put it in upload mode. +Small and convenient development board with 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. .. image:: http://dl.espressif.com/dl/schematics/pictures/esp32-core-board-v2.jpg :align: center @@ -35,7 +36,6 @@ Small and convenient development module with break out pin headers and minimum a * `ESP32-DevKitC Getting Started Guide `_ (PDF) - ESP32 Demo Board V2 ------------------- @@ -59,6 +59,7 @@ Development board that has dual port USB to serial converter for programming and :alt: ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 board * `Schematic `__ (PDF) +* `JTAG Debugging for ESP32 `__ ESP32 WROVER KIT V2 @@ -73,5 +74,5 @@ This is an updated version of ESP32 DevKitJ V1 described above with design impro * `Schematic `__ (PDF) * `ESP-WROVER-KIT Getting Started Guide `_ (PDF) - +* `JTAG Debugging for ESP32 `__ (PDF) From 23fc2ef0bdc46a2a5d4919efc50177bfc672d994 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Wed, 8 Mar 2017 21:00:27 +0100 Subject: [PATCH 03/57] USB to serial driver links --- docs/modules-and-boards.rst | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/modules-and-boards.rst b/docs/modules-and-boards.rst index 208ec442f..3f175c7f7 100644 --- a/docs/modules-and-boards.rst +++ b/docs/modules-and-boards.rst @@ -18,7 +18,7 @@ The smallest module intended for installation in final products. Can be also use * `Schematic `__ (PDF) * `Datasheet `__ (PDF) -* `ESP32 Module Reference Design `_ (ZIP) containing: OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32 Module Reference Design `_ (ZIP) containing OrCAD schematic, PCB layout, gerbers and BOM ESP32 Core Board V2 / ESP32 DevKitC @@ -32,8 +32,10 @@ Small and convenient development board with break out pin headers and minimum ad :alt: ESP32 Core Board V2 / ESP32 DevKitC board * `Schematic `__ (PDF) -* `ESP32 Development Board Reference Design `_ (ZIP) containing: OrCAD schematic, PCB layout, gerbers and BOM +* `ESP32 Development Board Reference Design `_ (ZIP) containing OrCAD schematic, PCB layout, gerbers and BOM * `ESP32-DevKitC Getting Started Guide `_ (PDF) +* `CP210x USB to UART Bridge VCP Drivers `_ + ESP32 Demo Board V2 @@ -46,6 +48,7 @@ One of first feature rich evaluation boards that contains several pin headers, d :alt: ESP32 Demo Board V2 board * `Schematic `__ (PDF) +* `FTDI Virtual COM Port Drivers`_ Note: Drivers install automatically on most of OS / there is no need to install them manually ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 @@ -59,7 +62,8 @@ Development board that has dual port USB to serial converter for programming and :alt: ESP32 WROVER KIT V1 / ESP32 DevKitJ V1 board * `Schematic `__ (PDF) -* `JTAG Debugging for ESP32 `__ +* `FTDI Virtual COM Port Drivers`_ Note: Drivers install automatically on most of OS / there is no need to install them manually +* `JTAG Debugging for ESP32`_ (PDF) ESP32 WROVER KIT V2 @@ -74,5 +78,10 @@ This is an updated version of ESP32 DevKitJ V1 described above with design impro * `Schematic `__ (PDF) * `ESP-WROVER-KIT Getting Started Guide `_ (PDF) -* `JTAG Debugging for ESP32 `__ (PDF) +* `FTDI Virtual COM Port Drivers`_ Note: Drivers install automatically on most of OS / there is no need to install them manually +* `JTAG Debugging for ESP32`_ (PDF) + + +.. _JTAG Debugging for ESP32: https://github.com/espressif/esp-idf/ +.. _FTDI Virtual COM Port Drivers: http://www.ftdichip.com/Drivers/D2XX.htm From 194d4e9ffdaefc53e72090ebdd07baf397c98ae3 Mon Sep 17 00:00:00 2001 From: Chu Shu Chen Date: Thu, 2 Mar 2017 16:13:30 +0800 Subject: [PATCH 04/57] fix(touch_pad): modify touch pad read function and touch_pad_deinit The touch pad read function taks too much time within spin lock waiting for the "done bit". (about 7.6ms as we tested) So we try to use a mutex on the touch read function and any other functions might change the "done bit". --- components/driver/include/driver/touch_pad.h | 17 +++++++-- components/driver/rtc_module.c | 38 ++++++++++++++++---- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/components/driver/include/driver/touch_pad.h b/components/driver/include/driver/touch_pad.h index 4f78b2351..e880ff611 100644 --- a/components/driver/include/driver/touch_pad.h +++ b/components/driver/include/driver/touch_pad.h @@ -43,10 +43,21 @@ typedef intr_handle_t touch_isr_handle_t; * *This function int touch pad module ,enable touch module * - * @return None + * @return + * - ESP_OK Success + * - ESP_FAIL Touch pad init error * */ -void touch_pad_init(); +esp_err_t touch_pad_init(); + +/** + * @brief Uninstall TouchPad driver. + * + * @return + * - ESP_OK Success + * - ESP_FAIL Touch pad deinit error + */ +esp_err_t touch_pad_deinit(); /** * @brief Configure touch pad interrupt threshold. @@ -60,6 +71,7 @@ void touch_pad_init(); * * @return - ESP_OK Success * - ESP_ERR_INVALID_ARG Touch pad error + * - ESP_FAIL Touch pad not initialized * */ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold); @@ -76,6 +88,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold); * * @return - ESP_OK Success * - ESP_ERR_INVALID_ARG Touch pad error + * - ESP_FAIL Touch pad not initialized * */ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value); diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 3d3cab068..2a8204db9 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -23,6 +23,7 @@ #include "dac.h" #include "freertos/FreeRTOS.h" #include "freertos/xtensa_api.h" +#include "freertos/semphr.h" static const char *RTC_MODULE_TAG = "RTC_MODULE"; @@ -37,6 +38,7 @@ static const char *RTC_MODULE_TAG = "RTC_MODULE"; } portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED; +static xSemaphoreHandle rtc_touch_sem = NULL; //Reg,Mux,Fun,IE,Up,Down,Rtc_number const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = { @@ -323,6 +325,7 @@ static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_nu static esp_err_t touch_pad_init_config(uint16_t sleep_cycle, uint16_t sample_cycle_num) { + xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S); SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR); @@ -336,13 +339,30 @@ static esp_err_t touch_pad_init_config(uint16_t sleep_cycle, uint16_t sample_cyc //Touch Pad Measure Time= 8Mhz SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, sample_cycle_num, SENS_TOUCH_MEAS_DELAY_S); //8Mhz portEXIT_CRITICAL(&rtc_spinlock); - + xSemaphoreGive(rtc_touch_sem); return ESP_OK; } -void touch_pad_init() +esp_err_t touch_pad_init() { - touch_pad_init_config(TOUCH_PAD_SLEEP_CYCLE_CONFIG, TOUCH_PAD_MEASURE_CYCLE_CONFIG); + if(rtc_touch_sem == NULL) { + rtc_touch_sem = xSemaphoreCreateMutex(); + } + if(rtc_touch_sem == NULL) { + return ESP_FAIL; + } + return touch_pad_init_config(TOUCH_PAD_SLEEP_CYCLE_CONFIG, TOUCH_PAD_MEASURE_CYCLE_CONFIG); +} + +esp_err_t touch_pad_deinit() +{ + + if(rtc_touch_sem == NULL) { + return ESP_FAIL; + } + vSemaphoreDelete(rtc_touch_sem); + rtc_touch_sem=NULL; + return ESP_OK; } static void touch_pad_counter_init(touch_pad_t touch_num) @@ -391,7 +411,9 @@ static esp_err_t touch_start(touch_pad_t touch_num) esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold) { + RTC_MODULE_CHECK(rtc_touch_sem != NULL, "Touch pad not initialized", ESP_FAIL); RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); + xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); portENTER_CRITICAL(&rtc_spinlock); //clear touch force ,select the Touch mode is Timer CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); @@ -407,18 +429,20 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold) //Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA); portEXIT_CRITICAL(&rtc_spinlock); + xSemaphoreGive(rtc_touch_sem); touch_pad_power_on(touch_num); toch_pad_io_init(touch_num); touch_pad_counter_init(touch_num); touch_start(touch_num); - return ESP_OK; } esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value) { RTC_MODULE_CHECK(touch_num < TOUCH_PAD_MAX, "Touch_Pad Num Err", ESP_ERR_INVALID_ARG); - RTC_MODULE_CHECK(touch_value!=NULL, "touch_value", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(touch_value != NULL, "touch_value", ESP_ERR_INVALID_ARG); + RTC_MODULE_CHECK(rtc_touch_sem != NULL, "Touch pad not initialized", ESP_FAIL); + xSemaphoreTake(rtc_touch_sem, portMAX_DELAY); uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG); portENTER_CRITICAL(&rtc_spinlock); SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (touch_num))); @@ -432,16 +456,18 @@ esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value) SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FORCE_M); SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S); + portEXIT_CRITICAL(&rtc_spinlock); while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {}; uint8_t shift = (touch_num & 1) ? SENS_TOUCH_MEAS_OUT1_S : SENS_TOUCH_MEAS_OUT0_S; *touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (touch_num / 2) * 4) >> shift; WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0); //force oneTime test end //clear touch force ,select the Touch mode is Timer + portENTER_CRITICAL(&rtc_spinlock); CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M); CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_FORCE_M); portEXIT_CRITICAL(&rtc_spinlock); - + xSemaphoreGive(rtc_touch_sem); return ESP_OK; } From 817bbb4bf92cff78846a8b0540d045285d04f121 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:18:22 +0800 Subject: [PATCH 05/57] nvs: add missing error code descriptions --- components/nvs_flash/include/nvs.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 5f7a93a7b..7deca5444 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -31,16 +31,16 @@ typedef uint32_t nvs_handle; #define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ #define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ #define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ -#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< TBA */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< The type of set or get operation doesn't match the type of value stored in NVS */ #define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ #define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ #define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ #define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ #define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ -#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< TBA */ -#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< TBA */ -#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< TBA */ -#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< TBA */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< Key name is too long */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ /** * @brief Mode of opening the non-volatile storage From 5a23ec4dc4dc39189f8de35d0adab522c56fe97d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:24:56 +0800 Subject: [PATCH 06/57] nvs: check that storage has at least one free page This change adds a check for the free page count to nvs_flash_init. Under normal operation, NVS keeps at least one free page available, except for transient states such as freeing up new page. Due to external factors (such as NVS partition size reduction) this free page could be lost, making NVS operation impossible. Previously this would cause an error when performing any nvs_set operation or opening a new namespace. With this change, an error is returned from nvs_flash_init to indicate that NVS partition is in such a state. --- components/nvs_flash/README.rst | 4 +++- components/nvs_flash/include/nvs.h | 1 + components/nvs_flash/include/nvs_flash.h | 6 +++++- components/nvs_flash/src/nvs_pagemanager.cpp | 5 +++++ components/nvs_flash/test_nvs_host/test_nvs.cpp | 17 +++++++++++++++++ docs/api/storage/nvs_flash.rst | 4 +++- 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index ade5518aa..f9602fc8b 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -9,10 +9,12 @@ Non-volatile storage (NVS) library is designed to store key-value pairs in flash Underlying storage ^^^^^^^^^^^^^^^^^^ -Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The range of flash sectors to be used by the library is provided to ``nvs_flash_init`` function. +Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The library uses the first partition with ``data`` type and ``nvs`` subtype. Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. +.. note:: if an NVS partition is truncated (for example, when the partition table layout is changed), its contents should be erased. ESP-IDF build system provides a ``make erase_flash`` target to erase all contents of the flash chip. + Keys and values ^^^^^^^^^^^^^^^ diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 7deca5444..6e5af231a 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -41,6 +41,7 @@ typedef uint32_t nvs_handle; #define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< Internal error; never returned by nvs_ API functions */ #define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */ #define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */ +#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */ /** * @brief Mode of opening the non-volatile storage diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index 0162a8f8a..8307fe352 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -21,7 +21,11 @@ extern "C" { /** * @brief Initialize NVS flash storage with layout given in the partition table. * - * @return ESP_OK if storage was successfully initialized. + * @return + * - ESP_OK if storage was successfully initialized. + * - ESP_ERR_NVS_NO_FREE_PAGES if the NVS storage contains no empty pages + * (which may happen if NVS partition was truncated) + * - one of the error codes from the underlying flash storage driver */ esp_err_t nvs_flash_init(void); diff --git a/components/nvs_flash/src/nvs_pagemanager.cpp b/components/nvs_flash/src/nvs_pagemanager.cpp index 768b30667..943f54f2f 100644 --- a/components/nvs_flash/src/nvs_pagemanager.cpp +++ b/components/nvs_flash/src/nvs_pagemanager.cpp @@ -105,6 +105,11 @@ esp_err_t PageManager::load(uint32_t baseSector, uint32_t sectorCount) } } + // partition should have at least one free page + if (mFreePageList.size() == 0) { + return ESP_ERR_NVS_NO_FREE_PAGES; + } + return ESP_OK; } diff --git a/components/nvs_flash/test_nvs_host/test_nvs.cpp b/components/nvs_flash/test_nvs_host/test_nvs.cpp index 282d4de48..ff35a84d1 100644 --- a/components/nvs_flash/test_nvs_host/test_nvs.cpp +++ b/components/nvs_flash/test_nvs_host/test_nvs.cpp @@ -1108,6 +1108,23 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]") } } +TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]") +{ + const size_t blob_size = 2048; // big enough so that only one can fit into a page + uint8_t blob[blob_size] = {0}; + SpiFlashEmulator emu(5); + TEST_ESP_OK( nvs_flash_init_custom(0, 5) ); + nvs_handle handle; + TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) ); + TEST_ESP_OK( nvs_set_blob(handle, "1", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "2", blob, blob_size) ); + TEST_ESP_OK( nvs_set_blob(handle, "3", blob, blob_size) ); + TEST_ESP_OK( nvs_commit(handle) ); + nvs_close(handle); + // first two pages are now full, third one is writable, last two are empty + // init should fail + TEST_ESP_ERR( nvs_flash_init_custom(0, 3), ESP_ERR_NVS_NO_FREE_PAGES ); +} TEST_CASE("dump all performance data", "[nvs]") { diff --git a/docs/api/storage/nvs_flash.rst b/docs/api/storage/nvs_flash.rst index ce1af9454..b6cf6f221 100644 --- a/docs/api/storage/nvs_flash.rst +++ b/docs/api/storage/nvs_flash.rst @@ -48,6 +48,7 @@ Macros .. doxygendefine:: ESP_ERR_NVS_PAGE_FULL .. doxygendefine:: ESP_ERR_NVS_INVALID_STATE .. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH +.. doxygendefine:: ESP_ERR_NVS_NO_FREE_PAGES Type Definitions ^^^^^^^^^^^^^^^^ @@ -61,6 +62,7 @@ Enumerations Functions ^^^^^^^^^ +.. doxygenfunction:: nvs_flash_init .. doxygenfunction:: nvs_open .. doxygenfunction:: nvs_set_i8 .. doxygenfunction:: nvs_set_u8 @@ -86,5 +88,5 @@ Functions .. doxygenfunction:: nvs_erase_all .. doxygenfunction:: nvs_commit .. doxygenfunction:: nvs_close -.. doxygenfunction:: nvs_flash_init + From 94b9898ca73a70e904ce023dfdc5cb82868370d4 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:27:27 +0800 Subject: [PATCH 07/57] phy_init: move NVS init into relevant function, check errors This change also modifies logging statements to print hexadecimal error codes, which are easier to look up. --- components/esp32/phy_init.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 5fbeeb7c8..e1b22d6a9 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -118,7 +118,7 @@ const esp_phy_init_data_t* esp_phy_get_init_data() } esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); if (err != ESP_OK) { - ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err); + ESP_LOGE(TAG, "failed to read PHY data partition (0x%x)", err); return NULL; } if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || @@ -167,10 +167,15 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) { - nvs_handle handle; - esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + esp_err_t err = nvs_flash_init(); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + ESP_LOGW(TAG, "%s: failed to initialize NVS (0x%x)", __func__, err); + return err; + } + nvs_handle handle; + err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } else { @@ -185,7 +190,7 @@ esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_da nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to open NVS namespace (0x%x)", __func__, err); return err; } else { @@ -202,7 +207,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, uint32_t cal_data_version; err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to get cal_version (0x%x)", __func__, err); return err; } uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); @@ -216,7 +221,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, size_t length = sizeof(cal_data_mac); err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length); if (err != ESP_OK) { - ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err); + ESP_LOGD(TAG, "%s: failed to get cal_mac (0x%x)", __func__, err); return err; } if (length != sizeof(cal_data_mac)) { @@ -234,7 +239,7 @@ static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, length = sizeof(*out_cal_data); err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length); if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err); + ESP_LOGE(TAG, "%s: failed to get cal_data(0x%x)", __func__, err); return err; } if (length != sizeof(*out_cal_data)) { @@ -267,7 +272,6 @@ static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, void esp_phy_load_cal_and_init(void) { #ifdef CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE - nvs_flash_init(); esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { calibration_mode = PHY_RF_CAL_NONE; @@ -285,7 +289,7 @@ void esp_phy_load_cal_and_init(void) } esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); if (err != ESP_OK) { - ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + ESP_LOGW(TAG, "failed to load RF calibration data (0x%x), falling back to full calibration", err); calibration_mode = PHY_RF_CAL_FULL; } From f59f13efd5afb2342b399e2af3d79375285fb506 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:35:20 +0800 Subject: [PATCH 08/57] examples: remove nvs_flash_init from examples which do not use NVS --- examples/get-started/blink/main/blink.c | 3 --- examples/get-started/hello_world/main/hello_world_main.c | 2 -- examples/peripherals/i2s/main/app_main.c | 3 --- .../peripherals/touch_pad_interrupt/main/tp_interrupt_main.c | 5 ----- examples/peripherals/touch_pad_read/main/tp_read_main.c | 4 ---- 5 files changed, 17 deletions(-) diff --git a/examples/get-started/blink/main/blink.c b/examples/get-started/blink/main/blink.c index f97572ac2..698bad218 100644 --- a/examples/get-started/blink/main/blink.c +++ b/examples/get-started/blink/main/blink.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/gpio.h" #include "sdkconfig.h" @@ -42,6 +40,5 @@ void blink_task(void *pvParameter) void app_main() { - nvs_flash_init(); xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL); } diff --git a/examples/get-started/hello_world/main/hello_world_main.c b/examples/get-started/hello_world/main/hello_world_main.c index c8b9f5f0c..e1955d875 100644 --- a/examples/get-started/hello_world/main/hello_world_main.c +++ b/examples/get-started/hello_world/main/hello_world_main.c @@ -10,7 +10,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" -#include "nvs_flash.h" void hello_task(void *pvParameter) { @@ -26,6 +25,5 @@ void hello_task(void *pvParameter) void app_main() { - nvs_flash_init(); xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL); } diff --git a/examples/peripherals/i2s/main/app_main.c b/examples/peripherals/i2s/main/app_main.c index 9c8f80fd5..8072cff6a 100644 --- a/examples/peripherals/i2s/main/app_main.c +++ b/examples/peripherals/i2s/main/app_main.c @@ -11,8 +11,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/i2s.h" #include @@ -48,7 +46,6 @@ void app_main() .data_in_num = -1 //Not used }; - nvs_flash_init(); i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM, &pin_config); diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c index fd4fe5b27..90f94f65f 100644 --- a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "esp_log.h" #include "driver/touch_pad.h" @@ -95,9 +93,6 @@ static void touch_pad_rtc_intr(void * arg) void app_main() { - ESP_LOGI(TAG, "Starting"); - nvs_flash_init(); - // Initialize touch pad peripheral ESP_LOGI(TAG, "Initializing touch pad"); touch_pad_init(); diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c index accfe5027..69bb87d17 100644 --- a/examples/peripherals/touch_pad_read/main/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -9,8 +9,6 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" #include "driver/touch_pad.h" @@ -34,8 +32,6 @@ void touch_pad_read_task(void *pvParameter) void app_main() { - nvs_flash_init(); - // Initialize touch pad peripheral touch_pad_init(); From 4813ab2d28081ca1f7682343e721485b1a53cd19 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 14 Mar 2017 21:39:44 +0800 Subject: [PATCH 09/57] examples: check return value of nvs_flash_init nvs_flash_init may return an error code in some cases, and applications should check this error code (or at least assert on it being ESP_OK, to make potential issues more immediately obvious). This change modifies all the examples which use NVS to check the error code. Most examples get a simple ESP_ERROR_CHECK assert, while NVS examples, OTA example, and NVS unit tests get a more verbose check which may be used in real applications. --- components/nvs_flash/test/test_nvs.c | 16 ++++++++++-- examples/bluetooth/blufi/main/blufi_main.c | 2 +- .../protocols/coap_client/main/coap_client.c | 2 +- .../protocols/coap_server/main/coap_server.c | 2 +- .../http_request/main/http_request_main.c | 2 +- .../https_request/main/https_request_main.c | 2 +- .../protocols/mdns/main/mdns_example_main.c | 2 +- .../openssl_client/main/openssl_client.c | 2 +- .../openssl_server/main/openssl_server.c | 2 +- examples/protocols/sntp/main/sntp_main.c | 2 +- .../storage/nvs_rw_blob/main/nvs_rw_blob.c | 15 ++++++++--- .../storage/nvs_rw_value/main/nvs_rw_value.c | 25 +++++++++++++------ examples/system/ota/main/ota_example.c | 16 +++++++++++- .../main/wpa2_enterprise_main.c | 2 +- 14 files changed, 68 insertions(+), 24 deletions(-) diff --git a/components/nvs_flash/test/test_nvs.c b/components/nvs_flash/test/test_nvs.c index db97879bc..07d01db46 100644 --- a/components/nvs_flash/test/test_nvs.c +++ b/components/nvs_flash/test/test_nvs.c @@ -6,14 +6,26 @@ #include "unity.h" #include "nvs.h" #include "nvs_flash.h" -#include "esp_spi_flash.h" +#include "esp_partition.h" +#include "esp_log.h" #include +static const char* TAG = "test_nvs"; TEST_CASE("various nvs tests", "[nvs]") { nvs_handle handle_1; - TEST_ESP_OK(nvs_flash_init()); + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + ESP_LOGW(TAG, "nvs_flash_init failed (0x%x), erasing partition and retrying", err); + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + TEST_ESP_ERR(nvs_open("test_namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND); TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_INVALID_HANDLE); diff --git a/examples/bluetooth/blufi/main/blufi_main.c b/examples/bluetooth/blufi/main/blufi_main.c index b46ffb464..d35ab7121 100644 --- a/examples/bluetooth/blufi/main/blufi_main.c +++ b/examples/bluetooth/blufi/main/blufi_main.c @@ -312,7 +312,7 @@ void app_main() { esp_err_t ret; - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); esp_bt_controller_init(); diff --git a/examples/protocols/coap_client/main/coap_client.c b/examples/protocols/coap_client/main/coap_client.c index 7c0df1afe..a45f748d4 100644 --- a/examples/protocols/coap_client/main/coap_client.c +++ b/examples/protocols/coap_client/main/coap_client.c @@ -199,7 +199,7 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/coap_server/main/coap_server.c b/examples/protocols/coap_server/main/coap_server.c index 75e3296f7..f23285388 100644 --- a/examples/protocols/coap_server/main/coap_server.c +++ b/examples/protocols/coap_server/main/coap_server.c @@ -185,7 +185,7 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); diff --git a/examples/protocols/http_request/main/http_request_main.c b/examples/protocols/http_request/main/http_request_main.c index 3831ae65b..130729f06 100644 --- a/examples/protocols/http_request/main/http_request_main.c +++ b/examples/protocols/http_request/main/http_request_main.c @@ -174,7 +174,7 @@ static void http_get_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&http_get_task, "http_get_task", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/https_request/main/https_request_main.c b/examples/protocols/https_request/main/https_request_main.c index b953252aa..305b56220 100644 --- a/examples/protocols/https_request/main/https_request_main.c +++ b/examples/protocols/https_request/main/https_request_main.c @@ -325,7 +325,7 @@ static void https_get_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL); } diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index d19fd1ae6..50b74e08c 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -178,7 +178,7 @@ static void mdns_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&mdns_task, "mdns_task", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/openssl_client/main/openssl_client.c b/examples/protocols/openssl_client/main/openssl_client.c index 69e16141b..16c9a0efa 100644 --- a/examples/protocols/openssl_client/main/openssl_client.c +++ b/examples/protocols/openssl_client/main/openssl_client.c @@ -220,6 +220,6 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); } diff --git a/examples/protocols/openssl_server/main/openssl_server.c b/examples/protocols/openssl_server/main/openssl_server.c index c74bb0e41..e1d0619d2 100755 --- a/examples/protocols/openssl_server/main/openssl_server.c +++ b/examples/protocols/openssl_server/main/openssl_server.c @@ -255,6 +255,6 @@ static void wifi_conn_init(void) void app_main(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); } diff --git a/examples/protocols/sntp/main/sntp_main.c b/examples/protocols/sntp/main/sntp_main.c index 438505d7b..5a29fcac8 100644 --- a/examples/protocols/sntp/main/sntp_main.c +++ b/examples/protocols/sntp/main/sntp_main.c @@ -93,7 +93,7 @@ void app_main() static void obtain_time(void) { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); diff --git a/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c index c0a865eb6..6232984f4 100644 --- a/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c +++ b/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c @@ -13,6 +13,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" +#include "esp_partition.h" #include "nvs_flash.h" #include "nvs.h" #include "driver/gpio.h" @@ -146,9 +147,17 @@ esp_err_t print_what_saved(void) void app_main() { - nvs_flash_init(); - - esp_err_t err; + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // NVS partition was truncated and needs to be erased + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + // Retry nvs_flash_init + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); err = print_what_saved(); if (err != ESP_OK) printf("Error (%d) reading data from NVS!\n", err); diff --git a/examples/storage/nvs_rw_value/main/nvs_rw_value.c b/examples/storage/nvs_rw_value/main/nvs_rw_value.c index 1b3e06b85..db01a6afc 100644 --- a/examples/storage/nvs_rw_value/main/nvs_rw_value.c +++ b/examples/storage/nvs_rw_value/main/nvs_rw_value.c @@ -13,23 +13,32 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" +#include "esp_partition.h" #include "nvs_flash.h" #include "nvs.h" void app_main() { - nvs_flash_init(); - - nvs_handle my_handle; - esp_err_t err; - - printf("\n"); + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // NVS partition was truncated and needs to be erased + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + // Retry nvs_flash_init + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); // Open - printf("Opening Non-Volatile Storage (NVS) ... "); + printf("\n"); + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle my_handle; err = nvs_open("storage", NVS_READWRITE, &my_handle); if (err != ESP_OK) { - printf("Error (%d) opening NVS!\n", err); + printf("Error (%d) opening NVS handle!\n", err); } else { printf("Done\n"); diff --git a/examples/system/ota/main/ota_example.c b/examples/system/ota/main/ota_example.c index 06ed81e63..bc910f70c 100644 --- a/examples/system/ota/main/ota_example.c +++ b/examples/system/ota/main/ota_example.c @@ -21,6 +21,7 @@ #include "esp_ota_ops.h" #include "esp_partition.h" +#include "nvs.h" #include "nvs_flash.h" #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID @@ -279,7 +280,20 @@ void main_task(void *pvParameter) void app_main() { - nvs_flash_init(); + // Initialize NVS. + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES) { + // OTA app partition table has a smaller NVS partition size than the non-OTA + // partition table. This size mismatch may cause NVS initialization to fail. + // If this happens, we erase NVS partition and initialize NVS again. + const esp_partition_t* nvs_partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + assert(nvs_partition && "partition table must have an NVS partition"); + ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) ); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + initialise_wifi(); xTaskCreate(&main_task, "main_task", 8192, NULL, 5, NULL); } diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index 7d325c76a..0932aec93 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -148,7 +148,7 @@ static void wpa2_enterprise_task(void *pvParameters) void app_main() { - nvs_flash_init(); + ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); xTaskCreate(&wpa2_enterprise_task, "wpa2_enterprise_task", 4096, NULL, 5, NULL); } From 447ffb23d5b441e9836a63d7798fd3ab6a0fc495 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 15 Mar 2017 16:51:52 +0800 Subject: [PATCH 10/57] nvs: print page state as text in nvs_dump --- components/nvs_flash/src/nvs_page.cpp | 29 ++++++++++++++++++++++++++- components/nvs_flash/src/nvs_page.hpp | 2 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index 80ccb1f6d..a24c7214b 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -811,10 +811,37 @@ void Page::invalidateCache() { mFindInfo = CachedFindInfo(); } + +const char* Page::pageStateToName(PageState ps) +{ + switch (ps) { + case PageState::CORRUPT: + return "CORRUPT"; + + case PageState::ACTIVE: + return "ACTIVE"; + + case PageState::FREEING: + return "FREEING"; + + case PageState::FULL: + return "FULL"; + + case PageState::INVALID: + return "INVALID"; + + case PageState::UNINITIALIZED: + return "UNINITIALIZED"; + + default: + assert(0 && "invalid state value"); + return ""; + } +} void Page::debugDump() const { - printf("state=%x addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (int) mState, mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); + printf("state=%x (%s) addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (uint32_t) mState, pageStateToName(mState), mBaseAddress, mSeqNumber, static_cast(mFirstUsedEntry), static_cast(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount); size_t skip = 0; for (size_t i = 0; i < ENTRY_COUNT; ++i) { printf("%3d: ", static_cast(i)); diff --git a/components/nvs_flash/src/nvs_page.hpp b/components/nvs_flash/src/nvs_page.hpp index c1f430cae..66b6e847c 100644 --- a/components/nvs_flash/src/nvs_page.hpp +++ b/components/nvs_flash/src/nvs_page.hpp @@ -220,6 +220,8 @@ protected: assert(entry < ENTRY_COUNT); return mBaseAddress + ENTRY_DATA_OFFSET + static_cast(entry) * ENTRY_SIZE; } + + static const char* pageStateToName(PageState ps); protected: From 7670e9363904def83ac245037825853ff2c43ead Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Wed, 8 Feb 2017 19:52:18 +0800 Subject: [PATCH 11/57] Feature: add ledc low speed channels 1. Add low speed channels for LEDC module. 2. Improve fade object allocate mechanism. 3. Improve ledc example, add 2 low speed channels in example. 4. Remove debug code 5. Improve the register bit field name of slow clock. --- components/driver/include/driver/ledc.h | 35 ++- components/driver/ledc.c | 246 +++++++++++++-------- components/esp32/include/soc/ledc_struct.h | 9 +- examples/peripherals/ledc/README.md | 1 + examples/peripherals/ledc/main/ledc_fade.c | 179 ++++++++------- 5 files changed, 274 insertions(+), 196 deletions(-) diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index af7c6b807..70e21d9e4 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -29,8 +29,7 @@ extern "C" { typedef enum { LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */ - //in this version, we only support high speed speed_mode. We will access low speed speed_mode later - //LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */ + LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */ LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */ } ledc_mode_t; @@ -137,8 +136,6 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf); * After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings. * * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, - * now we only support high-speed mode. - * We will access low-speed mode in next version * @param channel LEDC channel(0-7), select from ledc_channel_t * * @return @@ -152,7 +149,7 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * @brief LEDC stop. * Disable LEDC output, and set idle level * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel(0-7), select from ledc_channel_t * @param idle_level Set output idle level after LEDC stops. * @@ -165,7 +162,7 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl /** * @brief LEDC set channel frequency(Hz) * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * @param freq_hz Set the LEDC frequency * @@ -179,7 +176,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t /** * @brief LEDC get channel frequency(Hz) * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * * @return @@ -192,7 +189,7 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); * @brief LEDC set duty * Only after calling ledc_update_duty will the duty update. * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel(0-7), select from ledc_channel_t * @param duty Set the LEDC duty, the duty range is [0, (2**bit_num) - 1] * @@ -205,7 +202,7 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t /** * @brief LEDC get duty * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel(0-7), select from ledc_channel_t * * @return @@ -218,7 +215,7 @@ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * @brief LEDC set gradient * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect. * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel(0-7), select from ledc_channel_t * @param duty Set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1] * @param gradule_direction Set the direction of the gradient @@ -254,7 +251,7 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags, /** * @brief Configure LEDC settings * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_sel Timer index(0-3), there are 4 timers in LEDC module * @param div_num Timer clock divide number, the timer clock is divided from the selected clock source * @param bit_num The count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1) @@ -269,7 +266,7 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_ /** * @brief Reset LEDC timer * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * @return @@ -281,7 +278,7 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief Pause LEDC timer counter * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * @return @@ -294,7 +291,7 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief Resume LEDC timer * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * @return @@ -306,7 +303,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief Bind LEDC channel with the selected timer * - * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel index(0-7), select from ledc_channel_t * @param timer_idx LEDC timer index(0-3), select from ledc_timer_t * @@ -321,7 +318,6 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * Call ledc_fade_start() after this to start fading. * * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, - * For now we only support high-speed mode. We will access low-speed mode soon. * @param channel LEDC channel index(0-7), select from ledc_channel_t * @param target_duty Target duty of fading.( 0 - (2 ** bit_num - 1))) * @param scale Controls the increase or decrease step scale. @@ -331,6 +327,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num); @@ -339,7 +336,6 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel * Call ledc_fade_start() after this to start fading. * * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, - * For now we only support high-speed mode. We will access low-speed mode soon. * @param channel LEDC channel index(0-7), select from ledc_channel_t * @param target_duty Target duty of fading.( 0 - (2 ** bit_num - 1))) * @param max_fade_time_ms The maximum time of the fading ( ms ). @@ -348,6 +344,7 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success * - ESP_ERR_INVALID_STATE Fade function not installed. + * - ESP_FAIL Fade function init error */ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms); @@ -358,7 +355,6 @@ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. * * @return - * - ESP_ERR_NO_MEM No enough memory * - ESP_OK Success * - ESP_ERR_INVALID_STATE Fade function already installed. */ @@ -373,6 +369,7 @@ void ledc_fade_func_uninstall(); /** * @brief Start LEDC fading. * + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode * @param channel LEDC channel number * @param wait_done Whether to block until fading done. * @@ -381,7 +378,7 @@ void ledc_fade_func_uninstall(); * - ESP_ERR_INVALID_STATE Fade function not installed. * - ESP_ERR_INVALID_ARG Parameter error. */ -esp_err_t ledc_fade_start(ledc_channel_t channel, ledc_fade_mode_t wait_done); +esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t wait_done); #ifdef __cplusplus } diff --git a/components/driver/ledc.c b/components/driver/ledc.c index 6944f1b11..7da353869 100644 --- a/components/driver/ledc.c +++ b/components/driver/ledc.c @@ -41,7 +41,8 @@ typedef struct { xSemaphoreHandle ledc_fade_sem; xSemaphoreHandle ledc_fade_mux; } ledc_fade_t; -static ledc_fade_t* s_ledc_fade_rec = NULL; + +static ledc_fade_t *s_ledc_fade_rec[LEDC_SPEED_MODE_MAX][LEDC_CHANNEL_MAX]; static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL; #define LEDC_VAL_NO_CHANGE (-1) @@ -57,9 +58,24 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL; #define LEDC_FADE_TARGET_ERR_STR "LEDC fade target duty error" #define LEDC_FADE_INSTALLED_ERR_STR "LEDC fade service already installed" #define LEDC_FADE_MODE_ERR_STR "LEDC fade mode error" +#define LEDC_FADE_INIT_ERROR_STR "LEDC fade channel init error" +static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel) +{ + if (speed_mode == LEDC_LOW_SPEED_MODE) { + LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1; + } +} -esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src) +static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channel_t channel_num) +{ + if (speed_mode == LEDC_LOW_SPEED_MODE) { + LEDC.channel_group[speed_mode].channel[channel_num].conf0.low_speed_update = 1; + } +} + +esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, + ledc_clk_src_t clk_src) { LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG); LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG); @@ -67,9 +83,7 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_ LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num; LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src; LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num = bit_num; - if (speed_mode != LEDC_HIGH_SPEED_MODE) { - LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1; - } + ledc_ls_timer_update(speed_mode, timer_sel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -86,6 +100,7 @@ static IRAM_ATTR esp_err_t ledc_duty_config(ledc_mode_t speed_mode, ledc_channel ((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) | ((duty_cycle & LEDC_DUTY_CYCLE_HSCH0_V) << LEDC_DUTY_CYCLE_HSCH0_S) | ((duty_scale & LEDC_DUTY_SCALE_HSCH0_V) << LEDC_DUTY_SCALE_HSCH0_S); + ledc_ls_channel_update(speed_mode, channel_num); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -96,6 +111,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, ledc_channel_t channel LEDC_CHECK(timer_idx <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx; + ledc_ls_channel_update(speed_mode, channel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -107,6 +123,7 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel) portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1; LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0; + ledc_ls_timer_update(speed_mode, timer_sel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -117,6 +134,7 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel) LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1; + ledc_ls_timer_update(speed_mode, timer_sel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -127,6 +145,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel) LEDC_CHECK(timer_sel <= LEDC_TIMER_3, LEDC_TIMER_ERR_STR, ESP_ERR_INVALID_ARG); portENTER_CRITICAL(&ledc_spinlock); LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0; + ledc_ls_timer_update(speed_mode, timer_sel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -138,10 +157,14 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, uint32_t intr_type = type; portENTER_CRITICAL(&ledc_spinlock); value = LEDC.int_ena.val; + uint8_t int_en_base = LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S; + if (speed_mode == LEDC_LOW_SPEED_MODE) { + int_en_base = LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S; + } if (intr_type == LEDC_INTR_FADE_END) { - LEDC.int_ena.val = value | BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel); + LEDC.int_ena.val = value | BIT(int_en_base + channel); } else { - LEDC.int_ena.val = ( value & ( ~( BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel) ) ) ); + LEDC.int_ena.val = (value & (~(BIT(int_en_base + channel)))); } portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; @@ -188,12 +211,17 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf) if (div_param > LEDC_DIV_NUM_HSTIMER0_V) { // APB_CLK results in divisor which too high. Try using REF_TICK as clock source. timer_clk_src = LEDC_REF_TICK; - div_param = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / freq_hz / precision; + div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; if (div_param < 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { ESP_LOGE(LEDC_TAG, "requested frequency and bit depth can not be achieved, try increasing freq_hz or bit_num. div_param=%d", (uint32_t ) div_param); ret = ESP_FAIL; } + } else { + if (speed_mode == LEDC_LOW_SPEED_MODE) { + //for now, we only select 80mhz for slow clk of LEDC low speed channels. + LEDC.conf.slow_clk_sel = 1; + } } // set timer parameters ledc_timer_set(speed_mode, timer_num, div_param, bit_num, timer_clk_src); @@ -212,8 +240,7 @@ esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc if (speed_mode == LEDC_HIGH_SPEED_MODE) { gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0); } else { - ESP_LOGE(LEDC_TAG, "low speed mode is not implemented"); - return ESP_ERR_NOT_SUPPORTED; + gpio_matrix_out(gpio_num, LEDC_LS_SIG_OUT0_IDX + ledc_channel, 0, 0); } return ESP_OK; } @@ -248,7 +275,11 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf) /*set LEDC signal in gpio matrix*/ PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO); gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT); - gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0); + if (speed_mode == LEDC_HIGH_SPEED_MODE) { + gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0); + } else { + gpio_matrix_out(gpio_num, LEDC_LS_SIG_OUT0_IDX + ledc_channel, 0, 0); + } return ret; } @@ -259,6 +290,7 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel) portENTER_CRITICAL(&ledc_spinlock); LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1; LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1; + ledc_ls_channel_update(speed_mode, channel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -271,6 +303,7 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1; LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0; LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 0; + ledc_ls_channel_update(speed_mode, channel); portEXIT_CRITICAL(&ledc_spinlock); return ESP_OK; } @@ -285,7 +318,7 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t ESP_LOGE(LEDC_TAG, "step_num=%u duty_cyle_num=%u duty_scale=%u", step_num, duty_cyle_num, duty_scale); return ESP_ERR_INVALID_ARG; } - if (s_ledc_fade_rec) { + if (s_ledc_fade_rec[speed_mode][channel]) { ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE); } ledc_duty_config(speed_mode, @@ -304,7 +337,7 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t { LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG); LEDC_CHECK(channel <= LEDC_CHANNEL_7, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); - if (s_ledc_fade_rec) { + if (s_ledc_fade_rec[speed_mode][channel]) { ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_DISABLE); } ledc_duty_config(speed_mode, @@ -334,11 +367,11 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t uint32_t div_num = 0; uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num; uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel; - uint32_t precision = ( 0x1 << bit_num ); + uint32_t precision = (0x1 << bit_num); if (timer_source_clk == LEDC_APB_CLK) { - div_num = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision; + div_num = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision; } else { - div_num = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / freq_hz / precision; + div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision; } if (div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) { ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", div_num); @@ -351,81 +384,127 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num) { - LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ( 0 )); + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, (0)); portENTER_CRITICAL(&ledc_spinlock); uint32_t freq = 0; uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel; uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num; uint32_t div_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num; - uint32_t precision = ( 0x1 << bit_num ); + uint32_t precision = (0x1 << bit_num); if (timer_source_clk == LEDC_APB_CLK) { - freq = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / precision / div_num; + freq = ((uint64_t) LEDC_APB_CLK_HZ << 8) / precision / div_num; } else { - freq = ( (uint64_t) LEDC_REF_CLK_HZ << 8 ) / precision / div_num; + freq = ((uint64_t) LEDC_REF_CLK_HZ << 8) / precision / div_num; } portEXIT_CRITICAL(&ledc_spinlock); return freq; } -void IRAM_ATTR ledc_fade_isr() +void IRAM_ATTR ledc_fade_isr(void* arg) { - int i; + int channel; portBASE_TYPE HPTaskAwoken = pdFALSE; uint32_t intr_status = LEDC.int_st.val; //read LEDC interrupt status. LEDC.int_clr.val = intr_status; //clear LEDC interrupt status. - for (i = 0; i < 8; i++) { - if (intr_status & BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ST_S + i)) { - int speed_mode = s_ledc_fade_rec[i].speed_mode; - int duty_cur = LEDC.channel_group[speed_mode].channel[i].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM; - if (duty_cur == s_ledc_fade_rec[i].target_duty) { - if(s_ledc_fade_rec[i].mode == LEDC_FADE_WAIT_DONE) { - xSemaphoreGiveFromISR(s_ledc_fade_rec[i].ledc_fade_sem, &HPTaskAwoken); - if(HPTaskAwoken == pdTRUE) { - portYIELD_FROM_ISR() ; + int speed_mode = LEDC_HIGH_SPEED_MODE; + for (channel = 0; channel < LEDC_CHANNEL_MAX; channel++) { + if (intr_status & (BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ST_S + channel) | BIT(LEDC_DUTY_CHNG_END_LSCH0_INT_ST_S + channel))) { + if (intr_status & BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ST_S + channel)) { + speed_mode = LEDC_HIGH_SPEED_MODE; + } else { + speed_mode = LEDC_LOW_SPEED_MODE; + } + if (s_ledc_fade_rec[speed_mode][channel] == NULL) { + //fade object not initialized yet. + continue; + } + int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM; + if (duty_cur == s_ledc_fade_rec[speed_mode][channel]->target_duty) { + if (s_ledc_fade_rec[speed_mode][channel]->mode == LEDC_FADE_WAIT_DONE) { + xSemaphoreGiveFromISR(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, &HPTaskAwoken); + if (HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); } } continue; } - int duty_tar = s_ledc_fade_rec[i].target_duty; - int scale = s_ledc_fade_rec[i].scale; + int duty_tar = s_ledc_fade_rec[speed_mode][channel]->target_duty; + int scale = s_ledc_fade_rec[speed_mode][channel]->scale; if (scale == 0) { continue; } - int cycle = s_ledc_fade_rec[i].cycle_num; - int delta = s_ledc_fade_rec[i].direction == LEDC_DUTY_DIR_DECREASE ? duty_cur - duty_tar : duty_tar - duty_cur; + int cycle = s_ledc_fade_rec[speed_mode][channel]->cycle_num; + int delta = s_ledc_fade_rec[speed_mode][channel]->direction == LEDC_DUTY_DIR_DECREASE ? duty_cur - duty_tar : duty_tar - duty_cur; int step = delta / scale > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : delta / scale; - if (delta > scale) { ledc_duty_config( speed_mode, - i, + channel, LEDC_VAL_NO_CHANGE, duty_cur << LEDC_DUTY_DECIMAL_BIT_NUM, - s_ledc_fade_rec[i].direction, + s_ledc_fade_rec[speed_mode][channel]->direction, step, cycle, scale); } else { ledc_duty_config( speed_mode, - i, + channel, LEDC_VAL_NO_CHANGE, duty_tar << LEDC_DUTY_DECIMAL_BIT_NUM, - s_ledc_fade_rec[i].direction, + s_ledc_fade_rec[speed_mode][channel]->direction, 1, 1, 0); } - LEDC.channel_group[speed_mode].channel[i].conf1.duty_start = 1; + LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1; } } LEDC.int_clr.val = intr_status; //clear LEDC interrupt status. } +static esp_err_t ledc_fade_channel_deinit(ledc_mode_t speed_mode, ledc_channel_t channel) +{ + if (s_ledc_fade_rec[speed_mode][channel]) { + if (s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux) { + vSemaphoreDelete(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux); + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux = NULL; + } + if (s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem) { + vSemaphoreDelete(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem); + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem = NULL; + } + free(s_ledc_fade_rec[speed_mode][channel]); + s_ledc_fade_rec[speed_mode][channel] = NULL; + } + return ESP_OK; +} + +static esp_err_t ledc_fade_channel_init_check(ledc_mode_t speed_mode, ledc_channel_t channel) +{ + if (s_ledc_fade_rec[speed_mode][channel] == NULL) { + s_ledc_fade_rec[speed_mode][channel] = (ledc_fade_t *) calloc(1, sizeof(ledc_fade_t)); + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux = xSemaphoreCreateMutex(); + s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem = xSemaphoreCreateBinary(); + } + if (s_ledc_fade_rec[speed_mode][channel] + && s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux + && s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem) { + return ESP_OK; + } else { + ledc_fade_channel_deinit(speed_mode, channel); + return ESP_FAIL; + } +} + esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int max_fade_time_ms) { + LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG); + LEDC_CHECK(channel < LEDC_CHANNEL_MAX, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); + LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL); + int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel; - int max_duty = ( 1 << ( LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num ) ) - 1; + int max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1; LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG); uint32_t freq = ledc_get_freq(speed_mode, timer_sel); int duty_cur = LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM; @@ -441,16 +520,17 @@ esp_err_t ledc_set_fade_with_time(ledc_mode_t speed_mode, ledc_channel_t channel cycle_num = total_cycles / duty_delta; } else { cycle_num = 1; - scale = ( duty_delta + total_cycles - 1 ) / total_cycles; + scale = (duty_delta + total_cycles - 1) / total_cycles; } return ledc_set_fade_with_step(speed_mode, channel, target_duty, scale, cycle_num); } esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel, int target_duty, int scale, int cycle_num) { - LEDC_CHECK(s_ledc_fade_rec != NULL, LEDC_FADE_SERVICE_ERR_STR, ESP_ERR_INVALID_STATE); LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, LEDC_MODE_ERR_STR, ESP_ERR_INVALID_ARG); LEDC_CHECK(channel < LEDC_CHANNEL_MAX, LEDC_CHANNEL_ERR_STR, ESP_ERR_INVALID_ARG); + LEDC_CHECK(ledc_fade_channel_init_check(speed_mode, channel) == ESP_OK , LEDC_FADE_INIT_ERROR_STR, ESP_FAIL); + int timer_sel = LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel; int max_duty = (1 << (LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num)) - 1; LEDC_CHECK(target_duty <= max_duty, LEDC_FADE_TARGET_ERR_STR, ESP_ERR_INVALID_ARG); @@ -463,18 +543,18 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel if (duty_delta == 0) { return ESP_OK; } - s_ledc_fade_rec[channel].speed_mode = speed_mode; - s_ledc_fade_rec[channel].target_duty = target_duty; - s_ledc_fade_rec[channel].cycle_num = cycle_num; - s_ledc_fade_rec[channel].scale = scale; + s_ledc_fade_rec[speed_mode][channel]->speed_mode = speed_mode; + s_ledc_fade_rec[speed_mode][channel]->target_duty = target_duty; + s_ledc_fade_rec[speed_mode][channel]->cycle_num = cycle_num; + s_ledc_fade_rec[speed_mode][channel]->scale = scale; int step_num; if (duty_cur > target_duty) { - s_ledc_fade_rec[channel].direction = LEDC_DUTY_DIR_DECREASE; - step_num = ( duty_cur - target_duty ) / scale; + s_ledc_fade_rec[speed_mode][channel]->direction = LEDC_DUTY_DIR_DECREASE; + step_num = (duty_cur - target_duty) / scale; step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num; } else { - s_ledc_fade_rec[channel].direction = LEDC_DUTY_DIR_INCREASE; - step_num = ( target_duty - duty_cur ) / scale; + s_ledc_fade_rec[speed_mode][channel]->direction = LEDC_DUTY_DIR_INCREASE; + step_num = (target_duty - duty_cur) / scale; step_num = step_num > LEDC_STEP_NUM_MAX ? LEDC_STEP_NUM_MAX : step_num; } portEXIT_CRITICAL(&ledc_spinlock); @@ -483,42 +563,28 @@ esp_err_t ledc_set_fade_with_step(ledc_mode_t speed_mode, ledc_channel_t channel speed_mode, channel, duty_cur, - s_ledc_fade_rec[channel].direction, + s_ledc_fade_rec[speed_mode][channel]->direction, step_num, - s_ledc_fade_rec[channel].cycle_num, - s_ledc_fade_rec[channel].scale + s_ledc_fade_rec[speed_mode][channel]->cycle_num, + s_ledc_fade_rec[speed_mode][channel]->scale ); ESP_LOGD(LEDC_TAG, "cur duty: %d; target: %d, step: %d, cycle: %d; scale: %d\n", LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> LEDC_DUTY_DECIMAL_BIT_NUM, target_duty, step_num, - s_ledc_fade_rec[channel].cycle_num, - s_ledc_fade_rec[channel].scale + s_ledc_fade_rec[speed_mode][channel]->cycle_num, + s_ledc_fade_rec[speed_mode][channel]->scale ); - LEDC.int_clr.val |= BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel); + int bit_num_ch0 = (speed_mode == LEDC_HIGH_SPEED_MODE) ? LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S : LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S; + LEDC.int_clr.val |= BIT(bit_num_ch0 + channel); ledc_enable_intr_type(speed_mode, channel, LEDC_INTR_FADE_END); return ESP_OK; } esp_err_t ledc_fade_func_install(int intr_alloc_flags) { - LEDC_CHECK(s_ledc_fade_rec == NULL, LEDC_FADE_INSTALLED_ERR_STR, ESP_ERR_INVALID_STATE); - s_ledc_fade_rec = (ledc_fade_t*) calloc(LEDC_CHANNEL_MAX, sizeof(ledc_fade_t)); - if (s_ledc_fade_rec == NULL) { - return ESP_ERR_NO_MEM; - } - int i = 0; - for (i = 0; i < LEDC_CHANNEL_MAX; i++) { - s_ledc_fade_rec[i].ledc_fade_sem = xSemaphoreCreateBinary(); - s_ledc_fade_rec[i].ledc_fade_mux = xSemaphoreCreateMutex(); - if (s_ledc_fade_rec[i].ledc_fade_sem == NULL || s_ledc_fade_rec[i].ledc_fade_mux == NULL) { - ledc_fade_func_uninstall(); - return ESP_ERR_NO_MEM; - } - } //OR intr_alloc_flags with ESP_INTR_FLAG_IRAM because the fade isr is in IRAM - ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle); - return ESP_OK; + return ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle); } void ledc_fade_func_uninstall() @@ -526,42 +592,32 @@ void ledc_fade_func_uninstall() if (s_ledc_fade_rec == NULL) { return; } - if(s_ledc_fade_isr_handle) { + if (s_ledc_fade_isr_handle) { esp_intr_free(s_ledc_fade_isr_handle); s_ledc_fade_isr_handle = NULL; } - int i; - for (i = 0; i < LEDC_CHANNEL_MAX; i++) { - if (s_ledc_fade_rec[i].ledc_fade_sem) { - xSemaphoreHandle sem_tmp = s_ledc_fade_rec[i].ledc_fade_sem; - s_ledc_fade_rec[i].ledc_fade_sem = NULL; - vSemaphoreDelete(sem_tmp); - } - if (s_ledc_fade_rec[i].ledc_fade_mux) { - xSemaphoreHandle mux_tmp = s_ledc_fade_rec[i].ledc_fade_mux; - s_ledc_fade_rec[i].ledc_fade_mux = NULL; - vSemaphoreDelete(mux_tmp); + int channel, mode; + for (mode = 0; mode < LEDC_SPEED_MODE_MAX; mode++) { + for (channel = 0; channel < LEDC_CHANNEL_MAX; channel++) { + ledc_fade_channel_deinit(mode, channel); } } - free(s_ledc_fade_rec); - s_ledc_fade_rec = NULL; return; } -esp_err_t ledc_fade_start(ledc_channel_t channel, ledc_fade_mode_t wait_done) +esp_err_t ledc_fade_start(ledc_mode_t speed_mode, ledc_channel_t channel, ledc_fade_mode_t wait_done) { LEDC_CHECK(s_ledc_fade_rec != NULL, LEDC_FADE_SERVICE_ERR_STR, ESP_ERR_INVALID_STATE); LEDC_CHECK(wait_done < LEDC_FADE_MAX, LEDC_FADE_MODE_ERR_STR, ESP_ERR_INVALID_ARG); - int speed_mode = s_ledc_fade_rec[channel].speed_mode; - xSemaphoreTake(s_ledc_fade_rec[channel].ledc_fade_mux, portMAX_DELAY); + xSemaphoreTake(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux, portMAX_DELAY); if (wait_done == LEDC_FADE_WAIT_DONE) { - s_ledc_fade_rec[channel].mode = LEDC_FADE_WAIT_DONE; + s_ledc_fade_rec[speed_mode][channel]->mode = LEDC_FADE_WAIT_DONE; ledc_update_duty(speed_mode, channel); - xSemaphoreTake(s_ledc_fade_rec[channel].ledc_fade_sem, portMAX_DELAY); + xSemaphoreTake(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_sem, portMAX_DELAY); } else { - s_ledc_fade_rec[channel].mode = LEDC_FADE_NO_WAIT; + s_ledc_fade_rec[speed_mode][channel]->mode = LEDC_FADE_NO_WAIT; ledc_update_duty(speed_mode, channel); } - xSemaphoreGive(s_ledc_fade_rec[channel].ledc_fade_mux); + xSemaphoreGive(s_ledc_fade_rec[speed_mode][channel]->ledc_fade_mux); return ESP_OK; } diff --git a/components/esp32/include/soc/ledc_struct.h b/components/esp32/include/soc/ledc_struct.h index c52f67077..0745a2ec2 100644 --- a/components/esp32/include/soc/ledc_struct.h +++ b/components/esp32/include/soc/ledc_struct.h @@ -21,7 +21,8 @@ typedef volatile struct { uint32_t timer_sel: 2; /*There are four high speed timers the two bits are used to select one of them for high speed channel. 2'b00: seletc hstimer0. 2'b01: select hstimer1. 2'b10: select hstimer2. 2'b11: select hstimer3.*/ uint32_t sig_out_en: 1; /*This is the output enable control bit for high speed channel*/ uint32_t idle_lv: 1; /*This bit is used to control the output value when high speed channel is off.*/ - uint32_t reserved4: 27; + uint32_t low_speed_update: 1; /*This bit is only useful for low speed timer channels, reserved for high speed timers*/ + uint32_t reserved4: 26; uint32_t clk_en: 1; /*This bit is clock gating control signal. when software configure LED_PWM internal registers it controls the register clock.*/ }; uint32_t val; @@ -204,9 +205,13 @@ typedef volatile struct { } int_clr; union { struct { - uint32_t apb_clk_sel: 1; /*This bit is used to set the frequency of slow_clk. 1'b1:80mhz 1'b0:8mhz*/ + uint32_t apb_clk_sel: 1; /*This bit decides the slow clock for LEDC low speed channels, so we want to replace the field name with slow_clk_sel*/ uint32_t reserved1: 31; }; + struct { + uint32_t slow_clk_sel: 1; /*This bit is used to set the frequency of slow_clk. 1'b1:80mhz 1'b0:8mhz, (only used by LEDC low speed channels/timers)*/ + uint32_t reserved: 31; + }; uint32_t val; } conf; uint32_t reserved_194; diff --git a/examples/peripherals/ledc/README.md b/examples/peripherals/ledc/README.md index 9feea6b25..09a181a8b 100644 --- a/examples/peripherals/ledc/README.md +++ b/examples/peripherals/ledc/README.md @@ -14,3 +14,4 @@ * This example use GPIO18/19/4/5 as LEDC ouput, and it will change the duty repeatedly. + * GPIO18/19 are from high speed channel group. GPIO4/5 are from low speed channel group. diff --git a/examples/peripherals/ledc/main/ledc_fade.c b/examples/peripherals/ledc/main/ledc_fade.c index dcdb0462f..e9e453852 100644 --- a/examples/peripherals/ledc/main/ledc_fade.c +++ b/examples/peripherals/ledc/main/ledc_fade.c @@ -27,105 +27,124 @@ * * 4. This example use GPIO18/19/4/5 as LEDC ouput, and it will change the duty repeatedly. * + * 5. GPIO18/19 are from high speed channel group. GPIO4/5 are from low speed channel group. * */ +#define LEDC_HS_TIMER LEDC_TIMER_0 +#define LEDC_HS_MODE LEDC_HIGH_SPEED_MODE +#define LEDC_HS_CH0_GPIO (18) +#define LEDC_HS_CH0_CHANNEL LEDC_CHANNEL_0 +#define LEDC_HS_CH1_GPIO (19) +#define LEDC_HS_CH1_CHANNEL LEDC_CHANNEL_1 -#define LEDC_IO_0 (18) -#define LEDC_IO_1 (19) -#define LEDC_IO_2 (4) -#define LEDC_IO_3 (5) +#define LEDC_LS_TIMER LEDC_TIMER_1 +#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE +#define LEDC_LS_CH2_GPIO (4) +#define LEDC_LS_CH2_CHANNEL LEDC_CHANNEL_2 +#define LEDC_LS_CH3_GPIO (5) +#define LEDC_LS_CH3_CHANNEL LEDC_CHANNEL_3 -esp_err_t app_main() -{ - ledc_timer_config_t ledc_timer = { - //set timer counter bit number - .bit_num = LEDC_TIMER_13_BIT, - //set frequency of pwm - .freq_hz = 5000, - //timer mode, - .speed_mode = LEDC_HIGH_SPEED_MODE, - //timer index - .timer_num = LEDC_TIMER_0 +#define LEDC_TEST_CH_NUM (4) +typedef struct { + int channel; + int io; + int mode; + int timer_idx; +} ledc_info_t; + +void app_main() +{ + int ch; + ledc_info_t ledc_ch[LEDC_TEST_CH_NUM] = { + { + .channel = LEDC_HS_CH0_CHANNEL, + .io = LEDC_HS_CH0_GPIO, + .mode = LEDC_HS_MODE, + .timer_idx = LEDC_HS_TIMER + }, + { + .channel = LEDC_HS_CH1_CHANNEL, + .io = LEDC_HS_CH1_GPIO, + .mode = LEDC_HS_MODE, + .timer_idx = LEDC_HS_TIMER + }, + { + .channel = LEDC_LS_CH2_CHANNEL, + .io = LEDC_LS_CH2_GPIO, + .mode = LEDC_LS_MODE, + .timer_idx = LEDC_LS_TIMER + }, + { + .channel = LEDC_LS_CH3_CHANNEL, + .io = LEDC_LS_CH3_GPIO, + .mode = LEDC_LS_MODE, + .timer_idx = LEDC_LS_TIMER + } }; + + ledc_timer_config_t ledc_timer = { + .bit_num = LEDC_TIMER_13_BIT, //set timer counter bit number + .freq_hz = 5000, //set frequency of pwm + .speed_mode = LEDC_HS_MODE, //timer mode, + .timer_num = LEDC_HS_TIMER //timer index + }; + //configure timer0 for high speed channels ledc_timer_config(&ledc_timer); - ledc_channel_config_t ledc_channel = { - //set LEDC channel 0 - .channel = LEDC_CHANNEL_0, - //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) - .duty = 100, - //GPIO number - .gpio_num = LEDC_IO_0, - //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. - .intr_type = LEDC_INTR_FADE_END, - //set LEDC mode, from ledc_mode_t - .speed_mode = LEDC_HIGH_SPEED_MODE, - //set LEDC timer source, if different channel use one timer, - //the frequency and bit_num of these channels should be the same - .timer_sel = LEDC_TIMER_0 - }; - //set the configuration - ledc_channel_config(&ledc_channel); + //configure timer1 for low speed channels + ledc_timer.speed_mode = LEDC_LS_MODE; + ledc_timer.timer_num = LEDC_LS_TIMER; + ledc_timer_config(&ledc_timer); - //config ledc channel1 - ledc_channel.channel = LEDC_CHANNEL_1; - ledc_channel.gpio_num = LEDC_IO_1; - ledc_channel_config(&ledc_channel); - //config ledc channel2 - ledc_channel.channel = LEDC_CHANNEL_2; - ledc_channel.gpio_num = LEDC_IO_2; - ledc_channel_config(&ledc_channel); - //config ledc channel3 - ledc_channel.channel = LEDC_CHANNEL_3; - ledc_channel.gpio_num = LEDC_IO_3; - ledc_channel_config(&ledc_channel); + for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) { + ledc_channel_config_t ledc_channel = { + //set LEDC channel 0 + .channel = ledc_ch[ch].channel, + //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) + .duty = 0, + //GPIO number + .gpio_num = ledc_ch[ch].io, + //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. + .intr_type = LEDC_INTR_FADE_END, + //set LEDC mode, from ledc_mode_t + .speed_mode = ledc_ch[ch].mode, + //set LEDC timer source, if different channel use one timer, + //the frequency and bit_num of these channels should be the same + .timer_sel = ledc_ch[ch].timer_idx, + }; + //set the configuration + ledc_channel_config(&ledc_channel); + } //initialize fade service. ledc_fade_func_install(0); - - while(1) { + while (1) { printf("LEDC fade up\n"); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 1000, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 7000, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 5000, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3, 3000, 2000); - ledc_fade_start(LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_1, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_2, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_3, LEDC_FADE_NO_WAIT); + for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) { + ledc_set_fade_with_time(ledc_ch[ch].mode, ledc_ch[ch].channel, 4000, 2000); + ledc_fade_start(ledc_ch[ch].mode, ledc_ch[ch].channel, LEDC_FADE_NO_WAIT); + } vTaskDelay(3000 / portTICK_PERIOD_MS); printf("LEDC fade down\n"); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 100, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 300, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 500, 2000); - ledc_set_fade_with_time(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3, 700, 2000); - ledc_fade_start(LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_1, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_2, LEDC_FADE_NO_WAIT); - ledc_fade_start(LEDC_CHANNEL_3, LEDC_FADE_NO_WAIT); + for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) { + ledc_set_fade_with_time(ledc_ch[ch].mode, ledc_ch[ch].channel, 0, 2000); + ledc_fade_start(ledc_ch[ch].mode, ledc_ch[ch].channel, LEDC_FADE_NO_WAIT); + } vTaskDelay(3000 / portTICK_PERIOD_MS); printf("LEDC set duty without fade\n"); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 1000); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 7000); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 5000); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3, 3000); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3); - vTaskDelay(2000 / portTICK_PERIOD_MS); + for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) { + ledc_set_duty(ledc_ch[ch].mode, ledc_ch[ch].channel, 2000); + ledc_update_duty(ledc_ch[ch].mode, ledc_ch[ch].channel); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); printf("LEDC set duty without fade\n"); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0, 0); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1, 0); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2, 0); - ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3, 0); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_0); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_1); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_2); - ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL_3); - vTaskDelay(2000 / portTICK_PERIOD_MS); + for (ch = 0; ch < LEDC_TEST_CH_NUM; ch++) { + ledc_set_duty(ledc_ch[ch].mode, ledc_ch[ch].channel, 0); + ledc_update_duty(ledc_ch[ch].mode, ledc_ch[ch].channel); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); } } From a401169ea88f3d5b0a8fb4290931200ef35e10a6 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Fri, 17 Mar 2017 17:28:01 +0800 Subject: [PATCH 12/57] wpa2: add authenticate type for wpa2 enterprise --- components/esp32/include/esp_wifi_types.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esp32/include/esp_wifi_types.h b/components/esp32/include/esp_wifi_types.h index 88ad3dcf5..2b30f5b8b 100755 --- a/components/esp32/include/esp_wifi_types.h +++ b/components/esp32/include/esp_wifi_types.h @@ -49,11 +49,12 @@ typedef enum { } wifi_country_t; typedef enum { - WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */ - WIFI_AUTH_WEP, /**< authenticate mode : WEP */ - WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */ - WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ - WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ + WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */ + WIFI_AUTH_WEP, /**< authenticate mode : WEP */ + WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */ + WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ + WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ + WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */ WIFI_AUTH_MAX } wifi_auth_mode_t; From 94b91ee4af30f741ec8001331c358d2f596ed4ce Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Sun, 19 Mar 2017 16:09:44 +0800 Subject: [PATCH 13/57] bugfix: i2c driver not working in 'RELEASE' configuration This issue is reported from https://github.com/espressif/esp-idf/issues/304. We found that when we operate the hw command registers in I2C struct, sometimes the behaviour would be different in DEBUG/RELEASE optimisation level: The code looks like this: I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0; In DEBUG configuration: I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0; 400f3ab0: 3388 l32i.n a8, a3, 12 400f3ab2: 14c882 addi a8, a8, 20 400f3ab5: a08840 addx4 a8, a8, a4 400f3ab8: 0020c0 memw 400f3abb: 2898 l32i.n a9, a8, 8 400f3abd: 0020c0 memw 400f3ac0: 28b8 l32i.n a11, a8, 8 400f3ac2: 74a090 extui a10, a9, 0, 8 400f3ac5: 00af92 movi a9, 0xffffff00 400f3ac8: 109b90 and a9, a11, a9 400f3acb: 2099a0 or a9, a9, a10 400f3ace: 0020c0 memw 400f3ad1: 2899 s32i.n a9, a8, 8 In RELEASE configuration: I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= 0; 400f2ba2: 580572 l8ui a7, a5, 88 400f2ba5: 747070 extui a7, a7, 0, 8 400f2ba8: 0020c0 memw 400f2bab: 584572 s8i a7, a5, 88 Looks like the compiler will make it a 8bit operation after optimisation. But the register value changes from 0x901 to 0x101. After this 8-bit optimisation, the 11th bit changed from 1 to zero, which caused this error. We are still trying to find out why that happens, because there might be some risk when operating the register struct. This is a workaround to avoid "-=" operation on I2C register struct fields. --- components/driver/i2c.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 39eb87734..adfcfe7bf 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -862,19 +862,23 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = cmd->byte_num; I2C[i2c_num]->command[p_i2c->cmd_idx].op_code = cmd->op_code; if (cmd->op_code == I2C_CMD_WRITE) { + uint32_t wr_filled = 0; //TODO: to reduce interrupt number if (cmd->data) { while (p_i2c->tx_fifo_remain > 0 && cmd->byte_num > 0) { WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), *cmd->data++); p_i2c->tx_fifo_remain--; cmd->byte_num--; + wr_filled++; } } else { WRITE_PERI_REG(I2C_DATA_APB_REG(i2c_num), cmd->byte_cmd); p_i2c->tx_fifo_remain--; cmd->byte_num--; + wr_filled ++; } - I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num -= cmd->byte_num; + //Workaround for register field operation. + I2C[i2c_num]->command[p_i2c->cmd_idx].byte_num = wr_filled; I2C[i2c_num]->command[p_i2c->cmd_idx + 1].val = 0; I2C[i2c_num]->command[p_i2c->cmd_idx + 1].op_code = I2C_CMD_END; p_i2c->tx_fifo_remain = I2C_FIFO_LEN; From 1ad68de8b8036a1e91dbd1284273696a0c262821 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Sun, 19 Mar 2017 17:05:07 +0800 Subject: [PATCH 14/57] bugfix: I2C spikes on master init #393 from github Fix I2C spikes on master init. This issue is reported from https://github.com/espressif/esp-idf/issues/393 Before I2C io init, set high level on SDA/SCK IOs. --- components/driver/i2c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 39eb87734..914c5785e 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -66,6 +66,7 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 }; #define I2C_GPIO_PULLUP_ERR_STR "this i2c pin do not support internal pull-up" #define I2C_FIFO_FULL_THRESH_VAL (28) #define I2C_FIFO_EMPTY_THRESH_VAL (5) +#define I2C_IO_INIT_LEVEL (1) typedef struct { uint8_t byte_num; /*!< cmd byte number */ @@ -626,6 +627,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_ break; } if (sda_io_num >= 0) { + gpio_set_level(sda_io_num, I2C_IO_INIT_LEVEL); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[sda_io_num], PIN_FUNC_GPIO); gpio_set_direction(sda_io_num, GPIO_MODE_INPUT_OUTPUT_OD); if (sda_pullup_en == GPIO_PULLUP_ENABLE) { @@ -638,6 +640,7 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, gpio_num_t sda_io_num, gpio_num_t scl_ } if (scl_io_num >= 0) { + gpio_set_level(scl_io_num, I2C_IO_INIT_LEVEL); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[scl_io_num], PIN_FUNC_GPIO); if (mode == I2C_MODE_MASTER) { gpio_set_direction(scl_io_num, GPIO_MODE_INPUT_OUTPUT_OD); From bab7a2df805949e0119519852a3936b3dd3b9e34 Mon Sep 17 00:00:00 2001 From: Chu Shu Chen Date: Fri, 10 Mar 2017 21:30:30 +0800 Subject: [PATCH 15/57] add adc1 example --- examples/peripherals/adc/Makefile | 9 ++++++ examples/peripherals/adc/README.md | 17 +++++++++++ examples/peripherals/adc/main/adc1_test.c | 35 ++++++++++++++++++++++ examples/peripherals/adc/main/component.mk | 3 ++ 4 files changed, 64 insertions(+) create mode 100644 examples/peripherals/adc/Makefile create mode 100644 examples/peripherals/adc/README.md create mode 100644 examples/peripherals/adc/main/adc1_test.c create mode 100644 examples/peripherals/adc/main/component.mk diff --git a/examples/peripherals/adc/Makefile b/examples/peripherals/adc/Makefile new file mode 100644 index 000000000..937dac7c1 --- /dev/null +++ b/examples/peripherals/adc/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := adc + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/peripherals/adc/README.md b/examples/peripherals/adc/README.md new file mode 100644 index 000000000..de1532e21 --- /dev/null +++ b/examples/peripherals/adc/README.md @@ -0,0 +1,17 @@ +# Example: ADC1 + +This test code shows how to configure ADC1 and how to use ADC1 get the voltage. + + +####ADC1 functions: + + * ADC1,CHANNEL_4:GPIO32, voltage range [0v,3.1v],the Data range [0,4095] + + +####Test: + * Please connect the test voltage to GPIO32 + + + + + diff --git a/examples/peripherals/adc/main/adc1_test.c b/examples/peripherals/adc/main/adc1_test.c new file mode 100644 index 000000000..c8f406834 --- /dev/null +++ b/examples/peripherals/adc/main/adc1_test.c @@ -0,0 +1,35 @@ +/* ADC1 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 +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "driver/gpio.h" +#include "driver/adc.h" + +#define ADC1_TEST_CHANNEL (4) + +void adc1task(void* arg) +{ + // initialize ADC + adc1_config_width(ADC_WIDTH_12Bit); + adc1_config_channel_atten(ADC1_TEST_CHANNEL,ADC_ATTEN_11db); + while(1){ + printf("The adc1 value:%d\n",adc1_get_voltage(ADC1_TEST_CHANNEL)); + vTaskDelay(1000/portTICK_PERIOD_MS); + } +} + +void app_main() +{ + xTaskCreate(adc1task, "adc1task", 1024*3, NULL, 10, NULL); +} + diff --git a/examples/peripherals/adc/main/component.mk b/examples/peripherals/adc/main/component.mk new file mode 100644 index 000000000..44bd2b527 --- /dev/null +++ b/examples/peripherals/adc/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# From 39e728622f2c4d6ef7b29a3c408f1ca9ded2dc10 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 14 Mar 2017 18:55:12 +0800 Subject: [PATCH 16/57] build system: Call 'git status' w/ machine-readable output once to check submodules This is substantially faster than the 'git submodule status' command, has same effect. Particularly noticeable on Windows, where 'submodule status' takes 2 seconds and 'status' takes 0.2 seconds. --- make/project.mk | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/make/project.mk b/make/project.mk index e1a23e96e..6f43f4698 100644 --- a/make/project.mk +++ b/make/project.mk @@ -404,6 +404,9 @@ clean: config-clean # This only works for components inside IDF_PATH check-submodules: +# Dump the git status for the whole working copy once, then grep it for each submodule. This saves a lot of time on Windows. +GIT_STATUS := $(shell cd ${IDF_PATH} && git status --porcelain=v1 --ignore-submodules=dirty) + # Generate a target to check this submodule # $(1) - submodule directory, relative to IDF_PATH define GenerateSubmoduleCheckTarget @@ -415,9 +418,8 @@ $(IDF_PATH)/$(1)/.git: @echo "Attempting 'git submodule update --init $(1)' in esp-idf root directory..." cd ${IDF_PATH} && git submodule update --init $(1) -# Parse 'git submodule status' output for out-of-date submodule. -# Status output prefixes status line with '+' if the submodule commit doesn't match -ifneq ("$(shell cd ${IDF_PATH} && git submodule status $(1) | grep '^+')","") +# Parse 'git status' output to check if the submodule commit is different to expected +ifneq ("$(filter $(1),$(GIT_STATUS))","") $$(info WARNING: esp-idf git submodule $(1) may be out of date. Run 'git submodule update' in IDF_PATH dir to update.) endif endef From e477ce93e9257d5700f25df6366308682f00bb5a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 17 Mar 2017 18:41:18 +0800 Subject: [PATCH 17/57] idf_monitor: Small fixes (baud rate, EOL, /dev/tty.X on macOS, Ctrl-T on failure) * "make monitor" not passed the configured baud rate Closes #436 https://github.com/espressif/esp-idf/issues/436 * Pass toolchain prefix from sdkconfig into monitor tool * Allow setting EOL in idf_monitor.py, use CRLF by default * Detect if /dev/tty.X is used on macOS, warn and replace with /dev/cu.X * If a build fails or gdb exits, ignore Ctrl-T (allowing Ctrl-T Ctrl-A/F to be same key sequence everywhere) * Add a note about winpty on Windows Ref https://github.com/espressif/esp-idf/commit/02fdf8271de3a6db2ab9d4d6f023c160c84ebdbe#commitcomment-21369196 --- components/esptool_py/Makefile.projbuild | 4 ++- docs/idf-monitor.rst | 1 + tools/idf_monitor.py | 41 ++++++++++++++++++++---- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index 860e03838..b35dc1112 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -83,12 +83,14 @@ endif simple_monitor: $(call prereq_if_explicit,%flash) $(MONITOR_PYTHON) -m serial.tools.miniterm --rts 0 --dtr 0 --raw $(ESPPORT) $(MONITORBAUD) +MONITOR_OPTS := --baud $(MONITORBAUD) --port $(ESPPORT) --toolchain-prefix $(CONFIG_TOOLPREFIX) --make "$(MAKE)" + monitor: $(call prereq_if_explicit,%flash) $(summary) MONITOR [ -f $(APP_ELF) ] || echo "*** 'make monitor' target requires an app to be compiled and flashed first." [ -f $(APP_ELF) ] || echo "*** Run 'make flash monitor' to build, flash and monitor" [ -f $(APP_ELF) ] || echo "*** Or alternatively 'make simple_monitor' to view the serial port as-is." [ -f $(APP_ELF) ] || exit 1 - $(MONITOR_PYTHON) $(IDF_PATH)/tools/idf_monitor.py --port $(ESPPORT) --make "$(MAKE)" $(APP_ELF) + $(MONITOR_PYTHON) $(IDF_PATH)/tools/idf_monitor.py $(MONITOR_OPTS) $(APP_ELF) .PHONY: erase_flash diff --git a/docs/idf-monitor.rst b/docs/idf-monitor.rst index a0a2c5cba..61dfd0afd 100644 --- a/docs/idf-monitor.rst +++ b/docs/idf-monitor.rst @@ -102,6 +102,7 @@ Known Issues with idf_monitor Issues Observed on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~ +- If you are using the supported Windows environment and receive the error "winpty: command not found" then run ``pacman -S winpty`` to fix. - Arrow keys and some other special keys in gdb don't work, due to Windows Console limitations. - Occasionally when "make" exits, it may stall for up to 30 seconds before idf_monitor resumes. - Occasionally when "gdb" is run, it may stall for a short time before it begins communicating with the gdbstub. diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index 0bd5f3368..a8ddf77e7 100644 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -70,6 +70,8 @@ TAG_SERIAL = 1 # regex matches an potential PC value (0x4xxxxxxx) MATCH_PCADDR = re.compile(r'0x4[0-9a-f]{7}', re.IGNORECASE) +DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-" + class StoppableThread(object): """ Provide a Thread-like class which can be 'cancelled' via a subclass-provided @@ -193,7 +195,7 @@ class Monitor(object): Main difference is that all event processing happens in the main thread, not the worker threads. """ - def __init__(self, serial_instance, elf_file, make="make"): + def __init__(self, serial_instance, elf_file, make="make", toolchain_prefix=DEFAULT_TOOLCHAIN_PREFIX, eol="CRLF"): super(Monitor, self).__init__() self.event_queue = queue.Queue() self.console = miniterm.Console() @@ -207,9 +209,16 @@ class Monitor(object): self.serial_reader = SerialReader(self.serial, self.event_queue) self.elf_file = elf_file self.make = make + self.toolchain_prefix = DEFAULT_TOOLCHAIN_PREFIX self.menu_key = CTRL_T self.exit_key = CTRL_RBRACKET + self.translate_eol = { + "CRLF": lambda c: c.replace(b"\n", b"\r\n"), + "CR": lambda c: c.replace(b"\n", b"\r"), + "LF": lambda c: c.replace(b"\r", b"\n"), + }[eol] + # internal state self._pressed_menu_key = False self._read_line = b"" @@ -246,6 +255,7 @@ class Monitor(object): self.serial_reader.stop() else: try: + key = self.translate_eol(key) self.serial.write(codecs.encode(key)) except serial.SerialException: pass # this shouldn't happen, but sometimes port has closed in serial thread @@ -327,7 +337,9 @@ class Monitor(object): .format(key_description(CTRL_A))) sys.stderr.write("--- Press any other key to resume monitor (resets target).\n") sys.stderr.write(ANSI_NORMAL) - k = self.console.getkey() + k = CTRL_T # ignore CTRL-T here, so people can muscle-memory Ctrl-T Ctrl-F, etc. + while k == CTRL_T: + k = self.console.getkey() finally: self.console.cleanup() if k == self.exit_key: @@ -350,8 +362,8 @@ class Monitor(object): def lookup_pc_address(self, pc_addr): translation = subprocess.check_output( - ["xtensa-esp32-elf-addr2line", "-pfia", - "-e", self.elf_file, pc_addr], + ["%saddr2line" % self.toolchain_prefix, + "-pfia", "-e", self.elf_file, pc_addr], cwd=".") if not "?? ??:0" in translation: sys.stderr.write(ANSI_YELLOW + translation + ANSI_NORMAL) @@ -375,7 +387,7 @@ class Monitor(object): with self: # disable console control sys.stderr.write(ANSI_NORMAL) try: - subprocess.call(["xtensa-esp32-elf-gdb", + subprocess.call(["%sgdb" % self.toolchain_prefix, "-ex", "set serial baud %d" % self.serial.baudrate, "-ex", "target remote %s" % self.serial.port, "-ex", "interrupt", # monitor has already parsed the first 'reason' command, need a second @@ -404,12 +416,29 @@ def main(): help='Command to run make', type=str, default='make') + parser.add_argument( + '--toolchain-prefix', + help="Triplet prefix to add before cross-toolchain names", + default=DEFAULT_TOOLCHAIN_PREFIX) + + parser.add_argument( + "--eol", + choices=['CR', 'LF', 'CRLF'], + type=lambda c: c.upper(), + help="End of line to use when sending to the serial port", + default='CRLF') + parser.add_argument( 'elf_file', help='ELF file of application', type=argparse.FileType('r')) args = parser.parse_args() + if args.port.startswith("/dev/tty."): + args.port = args.port.replace("/dev/tty.", "/dev/cu.") + sys.stderr.write("WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched. ") + sys.stderr.write("Using %s instead...\n" % args.port) + serial_instance = serial.serial_for_url(args.port, args.baud, do_not_open=True) serial_instance.dtr = False @@ -428,7 +457,7 @@ def main(): except KeyError: pass # not running a make jobserver - monitor = Monitor(serial_instance, args.elf_file.name, args.make) + monitor = Monitor(serial_instance, args.elf_file.name, args.make, args.eol) sys.stderr.write('--- idf_monitor on {p.name} {p.baudrate} ---\n'.format( p=serial_instance)) From 5f3b9876b8088f89f5223484ad000cb4480d03f6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Mar 2017 16:08:06 +0800 Subject: [PATCH 18/57] idf_monitor: Fix issues using Ctrl-F/Ctrl-A/gdb with older pyserial Previously error was "AttributeError: 'Console' object has no attribute 'cancel'" --- tools/idf_monitor.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index a8ddf77e7..824a2f8e1 100644 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -148,7 +148,15 @@ class ConsoleReader(StoppableThread): self.console.cleanup() def _cancel(self): - self.console.cancel() + if hasattr(self.console, "cancel"): + self.console.cancel() + elif os.name == 'posix': + # this is the way cancel() is implemented in pyserial 3.1 or newer, + # older pyserial doesn't have this method, hence this hack. + # + # on Windows there is a different (also hacky) fix, applied above. + import fcntl, termios + fcntl.ioctl(self.console.fd, termios.TIOCSTI, b'\0') class SerialReader(StoppableThread): """ Read serial data from the serial port and push to the From 6afea0e81c55a91879e349fc5ed14824915276e7 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Mar 2017 16:29:57 +0800 Subject: [PATCH 19/57] linker scripts: Add explicit symbols for _iram_start and _flash_cache_start This is to avoid confusion when idf_monitor prints the first symbol in each section, ie "WindowOverflow4" or similar, when bootloader prints the section mapping address. Closes #447 https://github.com/espressif/esp-idf/issues/447 --- components/esp32/ld/esp32.common.ld | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index bc28e5ca9..4b1a35963 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -71,6 +71,10 @@ SECTIONS *(.init.literal) *(.init) _init_end = ABSOLUTE(.); + + /* This goes here, not at top of linker script, so addr2line finds it last, + and uses it in preference to the first symbol in IRAM */ + _iram_start = ABSOLUTE(0); } > iram0_0_seg .iram0.text : @@ -193,5 +197,11 @@ SECTIONS *(.gnu.version) _text_end = ABSOLUTE(.); _etext = .; + + /* Similar to _iram_start, this symbol goes here so it is + resolved by addr2line in preference to the first symbol in + the flash.text segment. + */ + _flash_cache_start = ABSOLUTE(0); } >iram0_2_seg } From 13f0737883ea3084bf60140f2231886c80f9fa3e Mon Sep 17 00:00:00 2001 From: Tian Hao Date: Tue, 21 Mar 2017 17:17:07 +0800 Subject: [PATCH 20/57] component/bt : fix blufi bug of sec_mode reset --- components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c index bf9ba35a0..737919257 100644 --- a/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c +++ b/components/bt/bluedroid/btc/profile/esp/blufi/blufi_prf.c @@ -268,6 +268,7 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) blufi_env.conn_id = p_data->conn.conn_id; blufi_env.is_connected = false; blufi_env.recv_seq = blufi_env.send_seq = 0; + blufi_env.sec_mode = 0x0; msg.sig = BTC_SIG_API_CB; msg.pid = BTC_PID_BLUFI; From a593d8a51831d4b3da2e4da986528b9837907376 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 15 Mar 2017 12:44:14 +0300 Subject: [PATCH 21/57] bugfix: fixed path to esptool when there is no compiled python module for it bugfix: GDB inernal failure handling was added --- components/espcoredump/espcoredump.py | 78 +++++++++++++++------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/components/espcoredump/espcoredump.py b/components/espcoredump/espcoredump.py index 521f211c1..a1091a006 100755 --- a/components/espcoredump/espcoredump.py +++ b/components/espcoredump/espcoredump.py @@ -695,7 +695,9 @@ class ESPCoreDumpFlashLoader(ESPCoreDumpLoader): super(ESPCoreDumpFlashLoader, self).__init__() if not tool_path: self.path = esptool.__file__ - self.path = self.path[:-1] + _,e = os.path.splitext(self.path) + if e == '.pyc': + self.path = self.path[:-1] else: self.path = tool_path self.port = port @@ -776,7 +778,7 @@ class GDBMIOutRecordHandler(object): """Base method to execute GDB/MI output record handler function """ if self.verbose: - print "%s.execute '%s'" % (self.__class__.__name__, ln) + print "%s.execute: [[%s]]" % (self.__class__.__name__, ln) class GDBMIOutStreamHandler(GDBMIOutRecordHandler): @@ -916,6 +918,37 @@ def info_corefile(args): out_handlers[h].execute(ln) break + def gdbmi_start(handlers): + p = subprocess.Popen( + bufsize = 0, + args = [args.gdb, + '--quiet', # inhibit dumping info at start-up + '--nx', # inhibit window interface + '--nw', # ignore .gdbinit + '--interpreter=mi2', # use GDB/MI v2 + '--core=%s' % core_fname, # core file + args.prog], + stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, + close_fds = CLOSE_FDS + ) + gdbmi_read2prompt(p.stdout, handlers) + return p + + def gdbmi_getinfo(p, handlers, gdb_cmd): + for t in handlers: + handlers[t].result_class = None + p.stdin.write("-interpreter-exec console \"%s\"\n" % gdb_cmd) + gdbmi_read2prompt(p.stdout, handlers) + if not handlers[GDBMIResultHandler.TAG].result_class or handlers[GDBMIResultHandler.TAG].result_class == GDBMIResultHandler.RC_EXIT: + print "GDB exited (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + p.wait() + print "Problem occured! GDB exited, restart it." + p = gdbmi_start(handlers) + elif handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE: + print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + return p + + loader = None if not args.core: loader = ESPCoreDumpFlashLoader(args.off, port=args.port) @@ -934,22 +967,6 @@ def info_corefile(args): loader.cleanup() return - handlers = {} - handlers[GDBMIResultHandler.TAG] = GDBMIResultHandler(verbose=False) - handlers[GDBMIStreamConsoleHandler.TAG] = GDBMIStreamConsoleHandler(None, verbose=False) - p = subprocess.Popen( - bufsize = 0, - args = [args.gdb, - '--quiet', # inhibit dumping info at start-up - '--nx', # inhibit window interface - '--nw', # ignore .gdbinit - '--interpreter=mi2', # use GDB/MI v2 - '--core=%s' % core_fname, # core file - args.prog], - stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, - close_fds = CLOSE_FDS - ) - gdbmi_read2prompt(p.stdout, handlers) exe_elf = ESPCoreDumpElfFile(args.prog) core_elf = ESPCoreDumpElfFile(core_fname) merged_segs = [] @@ -995,26 +1012,22 @@ def info_corefile(args): if not merged: merged_segs.append((s.name, s.addr, len(s.data), s.attr_str(), False)) + handlers = {} + handlers[GDBMIResultHandler.TAG] = GDBMIResultHandler(verbose=False) + handlers[GDBMIStreamConsoleHandler.TAG] = GDBMIStreamConsoleHandler(None, verbose=False) + p = gdbmi_start(handlers) + print "===============================================================" print "==================== ESP32 CORE DUMP START ====================" handlers[GDBMIResultHandler.TAG].result_class = None handlers[GDBMIStreamConsoleHandler.TAG].func = gdbmi_console_stream_handler print "\n================== CURRENT THREAD REGISTERS ===================" - p.stdin.write("-interpreter-exec console \"info registers\"\n") - gdbmi_read2prompt(p.stdout, handlers) - if handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE: - print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + p = gdbmi_getinfo(p, handlers, "info registers") print "\n==================== CURRENT THREAD STACK =====================" - p.stdin.write("-interpreter-exec console \"bt\"\n") - gdbmi_read2prompt(p.stdout, handlers) - if handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE: - print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + p = gdbmi_getinfo(p, handlers, "bt") print "\n======================== THREADS INFO =========================" - p.stdin.write("-interpreter-exec console \"info threads\"\n") - gdbmi_read2prompt(p.stdout, handlers) - if handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE: - print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + p = gdbmi_getinfo(p, handlers, "info threads") print "\n======================= ALL MEMORY REGIONS ========================" print "Name Address Size Attrs" for ms in merged_segs: @@ -1025,10 +1038,7 @@ def info_corefile(args): print "\n====================== CORE DUMP MEMORY CONTENTS ========================" for cs in core_elf.program_segments: print ".coredump.tasks 0x%x 0x%x %s" % (cs.addr, len(cs.data), cs.attr_str()) - p.stdin.write("-interpreter-exec console \"x/%dx 0x%x\"\n" % (len(cs.data)/4, cs.addr)) - gdbmi_read2prompt(p.stdout, handlers) - if handlers[GDBMIResultHandler.TAG].result_class != GDBMIResultHandler.RC_DONE: - print "GDB/MI command failed (%s / %s)!" % (handlers[GDBMIResultHandler.TAG].result_class, handlers[GDBMIResultHandler.TAG].result_str) + p = gdbmi_getinfo(p, handlers, "x/%dx 0x%x" % (len(cs.data)/4, cs.addr)) print "\n===================== ESP32 CORE DUMP END =====================" print "===============================================================" From c30bba8c63120b19e15779c6459624958fed23df Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 12:30:34 +0800 Subject: [PATCH 22/57] rmt driver: Fix parameter & description of rmt_driver_install Closes #187 https://github.com/espressif/esp-idf/issues/187 --- components/driver/include/driver/rmt.h | 15 +++++---------- components/driver/rmt.c | 6 +++--- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index 36e33e732..f5e82b4a1 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -619,22 +619,17 @@ esp_err_t rmt_fill_tx_items(rmt_channel_t channel, rmt_item32_t* item, uint16_t * * @param channel RMT channel (0 - 7) * - * @param rx_buf_size Size of RMT RX ringbuffer. + * @param rx_buf_size Size of RMT RX ringbuffer. Can be 0 if the RX ringbuffer is not used. * - * @note - * If we do not need RX ringbuffer, just set rx_buf_size to 0. - * - * @note - * When we call rmt_driver_install function, it will register a driver ISR handler, - * DO NOT REGISTER ISR HANDLER AGAIN. - * - * @param rmt_intr_num RMT interrupt number. + * @param intr_alloc_flags Flags for the RMT driver interrupt handler. Pass 0 for default flags. See esp_intr_alloc.h for details. * * @return + * - ESP_ERR_INVALID_STATE Driver is already installed, call rmt_driver_uninstall first. + * - ESP_ERR_NO_MEM Memory allocation failure * - ESP_ERR_INVALID_ARG Parameter error * - ESP_OK Success */ -esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int rmt_intr_num); +esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr_alloc_flags); /** * @brief Uninstall RMT driver. diff --git a/components/driver/rmt.c b/components/driver/rmt.c index d277ea00c..6ff1fb671 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -643,15 +643,15 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr { RMT_CHECK(channel < RMT_CHANNEL_MAX, RMT_CHANNEL_ERROR_STR, ESP_ERR_INVALID_ARG); if(p_rmt_obj[channel] != NULL) { - ESP_LOGD(RMT_TAG, "RMT DRIVER ALREADY INSTALLED"); - return ESP_FAIL; + ESP_LOGD(RMT_TAG, "RMT driver already installed"); + return ESP_ERR_INVALID_STATE; } p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t)); if(p_rmt_obj[channel] == NULL) { ESP_LOGE(RMT_TAG, "RMT driver malloc error"); - return ESP_FAIL; + return ESP_ERR_NO_MEM; } memset(p_rmt_obj[channel], 0, sizeof(rmt_obj_t)); From 64f26be0539b54f5bab4656bc85173cb19ad11ec Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 14:29:16 +0800 Subject: [PATCH 23/57] rmt driver: Remove accidental ESP_LOGE in isr handler Closes #451 https://github.com/espressif/esp-idf/issues/451 --- components/driver/rmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/driver/rmt.c b/components/driver/rmt.c index 6ff1fb671..c216c7475 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -555,7 +555,7 @@ static void IRAM_ATTR rmt_driver_isr_default(void* arg) if(p_rmt->rx_buf) { BaseType_t res = xRingbufferSendFromISR(p_rmt->rx_buf, (void*) RMTMEM.chan[channel].data32, item_len * 4, &HPTaskAwoken); if(res == pdFALSE) { - ESP_LOGE(RMT_TAG, "RMT RX BUFFER FULL"); + ESP_EARLY_LOGE(RMT_TAG, "RMT RX BUFFER FULL"); } else { } From 8438b8aa9287f803c258dd894ab06ec142df7406 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 14:41:44 +0800 Subject: [PATCH 24/57] bt: Fix typo ESP_BT_MODE_ILDE Closes #450 https://github.com/espressif/esp-idf/issues/450 --- components/bt/include/bt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index 2c652466b..e3bd7f084 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -27,7 +27,7 @@ extern "C" { * @brief Bluetooth mode for controller enable/disable */ typedef enum { - ESP_BT_MODE_ILDE = 0x00, /*!< Bluetooth is not run */ + ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not running */ ESP_BT_MODE_BLE = 0x01, /*!< Run BLE mode */ ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Run Classic BT mode */ ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */ From 36e685580a5d35fa9b657f5cf6e9aef28a32848c Mon Sep 17 00:00:00 2001 From: "rudi ;-)" Date: Fri, 17 Mar 2017 21:23:44 +0100 Subject: [PATCH 25/57] README: Remove link typo link typo removed char > from end of the link products/hardware/esp32/overview Merges #439 https://github.com/espressif/esp-idf/issues/450 Closes #437 https://github.com/espressif/esp-idf/issues/437 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c1b08e73d..7d8934f6c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![alt text](https://readthedocs.org/projects/docs/badge/?version=latest "Documentation Status")](http://esp-idf.readthedocs.io/en/latest/?badge=latest) -ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview>) chip. +ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip. # Developing With the ESP-IDF From 6a58e173b8d47832bbdf01f81140af37ead430d1 Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sun, 19 Mar 2017 12:06:37 -0700 Subject: [PATCH 26/57] build: pass more arguments to git describe so that it always works even if detached branch, etc Merges #441 https://github.com/espressif/esp-idf/pull/441 --- make/project.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/make/project.mk b/make/project.mk index e1a23e96e..f5ae796f0 100644 --- a/make/project.mk +++ b/make/project.mk @@ -186,8 +186,7 @@ endif @echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS) -# Git version of ESP-IDF (of the form v1.0-285-g5c4f707) -IDF_VER := $(shell git -C $(IDF_PATH) describe) +IDF_VER := $(shell git -C $(IDF_PATH) describe --always --tags --dirty) # Set default LDFLAGS From 0aab67f0aa10bb6a146e4fb3f35227763b83aee6 Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sun, 19 Mar 2017 11:34:35 -0700 Subject: [PATCH 27/57] esp32: esp_wifi.h: Replace a non-working #error statement with a working _Static_assert statement Merges #440 https://github.com/espressif/esp-idf/pull/440 --- components/esp32/include/esp_wifi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 05a686a36..a9b072200 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -135,7 +135,7 @@ typedef struct { .magic = WIFI_INIT_CONFIG_MAGIC\ }; #else -#define WIFI_INIT_CONFIG_DEFAULT #error Wifi is disabled in config, WIFI_INIT_CONFIG_DEFAULT will not work +#define WIFI_INIT_CONFIG_DEFAULT() {0}; _Static_assert(0, "please enable wifi in menuconfig to use esp_wifi.h"); #endif /** From 5272bd899bd09d344f08880d5aee5ecf106a6dff Mon Sep 17 00:00:00 2001 From: Edmund Huber Date: Sun, 19 Mar 2017 23:11:13 -0700 Subject: [PATCH 28/57] build: Check for .git, but it doesn't have to be a directory, so that esp-idf will work as a submodule Merges #438 https://github.com/espressif/esp-idf/pull/438 --- make/project.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/project.mk b/make/project.mk index f5ae796f0..9980e5800 100644 --- a/make/project.mk +++ b/make/project.mk @@ -409,7 +409,7 @@ define GenerateSubmoduleCheckTarget check-submodules: $(IDF_PATH)/$(1)/.git $(IDF_PATH)/$(1)/.git: @echo "WARNING: Missing submodule $(1)..." - [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) + [ -e ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule init $(1)' in esp-idf root directory."; exit 1) @echo "Attempting 'git submodule update --init $(1)' in esp-idf root directory..." cd ${IDF_PATH} && git submodule update --init $(1) From eba6789e6c04a6a364a5396e1a0c1d041f9504cc Mon Sep 17 00:00:00 2001 From: alarruskain Date: Mon, 13 Mar 2017 13:31:01 +0100 Subject: [PATCH 29/57] Fix late argument verification in emac-main Prevent crash when emac_phy_power_enable is not set. Merges #426 https://github.com/espressif/esp-idf/pull/426 --- components/ethernet/emac_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/ethernet/emac_main.c b/components/ethernet/emac_main.c index 8c93a1830..672ab75df 100644 --- a/components/ethernet/emac_main.c +++ b/components/ethernet/emac_main.c @@ -948,14 +948,14 @@ esp_err_t esp_eth_init(eth_config_t *config) emac_set_user_config_data(config); } - emac_config.emac_phy_power_enable(true); - ret = emac_verify_args(); if (ret != ESP_OK) { goto _exit; } + emac_config.emac_phy_power_enable(true); + //before set emac reg must enable clk emac_enable_clk(true); REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII); From 3e7b786af5d5b7f9b93054b551691d8306284ed6 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 7 Mar 2017 18:20:33 +0100 Subject: [PATCH 30/57] component/bt: allow to use alternative Bluetooth stack by disabling Bluedroid Merges #408 https://github.com/espressif/esp-idf/pull/440 --- components/bt/Kconfig | 9 ++++++++- components/bt/component.mk | 35 +++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 63dce8d1f..9b329e61e 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -1,7 +1,14 @@ menuconfig BT_ENABLED bool "Bluetooth" help - Select this option to enable Bluetooth stack and show the submenu with Bluetooth configuration choices. + Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices. + +config BLUEDROID_ENABLED + bool "Bluedroid Bluetooth stack enabled" + depends on BT_ENABLED + default y + help + This enables the default Bluedroid Bluetooth stack config BTC_TASK_STACK_SIZE int "Bluetooth event (callback to application) task stack size" diff --git a/components/bt/component.mk b/components/bt/component.mk index 12cc08841..f93cc5204 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -3,7 +3,26 @@ # ifdef CONFIG_BT_ENABLED -COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \ +COMPONENT_SRCDIRS := . + +COMPONENT_ADD_INCLUDEDIRS := include + +LIBS := btdm_app + +COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \ + $(addprefix -l,$(LIBS)) + +# re-link program if BT binary libs change +COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) + +COMPONENT_SUBMODULES += lib + +endif + + +ifdef CONFIG_BLUEDROID_ENABLED + +COMPONENT_ADD_INCLUDEDIRS += bluedroid/bta/include \ bluedroid/bta/sys/include \ bluedroid/btcore/include \ bluedroid/device/include \ @@ -29,17 +48,8 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \ bluedroid/stack/include \ bluedroid/api/include \ bluedroid/include \ - include -LIBS := btdm_app - -COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \ - $(addprefix -l,$(LIBS)) - -# re-link program if BT binary libs change -COMPONENT_ADD_LINKER_DEPS := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) - -COMPONENT_SRCDIRS := bluedroid/bta/dm \ +COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/bta/gatt \ bluedroid/bta/hh \ bluedroid/bta/sdp \ @@ -69,8 +79,5 @@ COMPONENT_SRCDIRS := bluedroid/bta/dm \ bluedroid/stack \ bluedroid/api \ bluedroid \ - . - -COMPONENT_SUBMODULES += lib endif From 01ad387ac82194341f17ef2ab49ba2a8c38ccdfb Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Mon, 20 Mar 2017 22:32:01 +0100 Subject: [PATCH 31/57] freertos: Add config parameters to customize FreeRTOS behaviour. The options are: - SUPPORT_STATIC_ALLOCATION - ENABLE_STATIC_TASK_CLEAN_UP_HOOK - TIMER_TASK_PRIORITY - TIMER_TASK_STACK_DEPTH - TIMER_QUEUE_LENGTH Merges #444 https://github.com/espressif/esp-idf/pull/444 --- components/freertos/Kconfig | 75 +++++++++++++++++++ .../include/freertos/FreeRTOSConfig.h | 14 +++- components/freertos/tasks.c | 6 +- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index b4bcfc3fe..dd9a95b06 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -197,6 +197,81 @@ config FREERTOS_MAX_TASK_NAME_LEN For most uses, the default of 16 is OK. +config SUPPORT_STATIC_ALLOCATION + bool "Enable FreeRTOS static allocation API" + default n + help + FreeRTOS gives the application writer the ability to instead provide the memory + themselves, allowing the following objects to optionally be created without any + memory being allocated dynamically: + + - Tasks + - Software Timers + - Queues + - Event Groups + - Binary Semaphores + - Counting Semaphores + - Recursive Semaphores + - Mutexes + + Whether it is preferable to use static or dynamic memory allocation is dependent on + the application, and the preference of the application writer. Both methods have pros + and cons, and both methods can be used within the same RTOS application. + + Creating RTOS objects using statically allocated RAM has the benefit of providing the + application writer with more control: RTOS objects can be placed at specific memory locations. + The maximum RAM footprint can be determined at link time, rather than run time. + The application writer does not need to concern themselves with graceful handling of memory allocation failures. + It allows the RTOS to be used in applications that simply don't allow any dynamic memory allocation + (although FreeRTOS includes allocation schemes that can overcome most objections). + +config ENABLE_STATIC_TASK_CLEAN_UP_HOOK + bool "Enable static task clean up hook" + depends on SUPPORT_STATIC_ALLOCATION + default n + help + Enable this option to make FreeRTOS call the static task clean up hook when a task is deleted. + + Bear in mind that if this option is enabled you will need to implement the following function: + + void vPortCleanUpTCB ( void *pxTCB ) { + // place clean up code here + } + +config TIMER_TASK_PRIORITY + int "FreeRTOS timer task priority" + range 1 25 + default 1 + help + The timer service task (primarily) makes use of existing FreeRTOS features, allowing timer + functionality to be added to an application with minimal impact on the size of the application's + executable binary. + + Use this constant to define the priority that the timer task will run at. + +config TIMER_TASK_STACK_DEPTH + int "FreeRTOS timer task stack size" + range 1536 32768 + default 2048 + help + The timer service task (primarily) makes use of existing FreeRTOS features, allowing timer + functionality to be added to an application with minimal impact on the size of the application's + executable binary. + + Use this constant to define the size (in bytes) of the stack allocated for the timer task. + +config TIMER_QUEUE_LENGTH + int "FreeRTOS timer queue length" + range 5 20 + default 10 + help + FreeRTOS provides a set of timer related API functions. Many of these functions use a standard + FreeRTOS queue to send commands to the timer service task. The queue used for this purpose is + called the 'timer command queue'. The 'timer command queue' is private to the FreeRTOS timer + implementation, and cannot be accessed directly. + + For most uses the default value of 10 is OK. + menuconfig FREERTOS_DEBUG_INTERNALS bool "Debug FreeRTOS internals" default n diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index 4f4033039..250879f30 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -248,13 +248,21 @@ #define configUSE_NEWLIB_REENTRANT 1 #define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configSUPPORT_STATIC_ALLOCATION CONFIG_SUPPORT_STATIC_ALLOCATION + +#ifndef __ASSEMBLER__ +#if CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK +extern void vPortCleanUpTCB ( void *pxTCB ); +#define portCLEAN_UP_TCB( pxTCB ) vPortCleanUpTCB( pxTCB ) +#endif +#endif /* Test FreeRTOS timers (with timer task) and more. */ /* Some files don't compile if this flag is disabled */ #define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY 1 -#define configTIMER_QUEUE_LENGTH 10 -#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE +#define configTIMER_TASK_PRIORITY CONFIG_TIMER_TASK_PRIORITY +#define configTIMER_QUEUE_LENGTH CONFIG_TIMER_QUEUE_LENGTH +#define configTIMER_TASK_STACK_DEPTH CONFIG_TIMER_TASK_STACK_DEPTH #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_eTaskGetState 1 diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index b37e59254..145554a74 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3763,11 +3763,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) static void prvDeleteTCB( TCB_t *pxTCB ) { - /* This call is required specifically for the TriCore port. It must be - above the vPortFree() calls. The call is also used by ports/demos that - want to allocate and clean RAM statically. */ - portCLEAN_UP_TCB( pxTCB ); - /* Free up the memory allocated by the scheduler for the task. It is up to the task to free any memory allocated at the application level. */ #if ( configUSE_NEWLIB_REENTRANT == 1 ) @@ -3806,6 +3801,7 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) /* Neither the stack nor the TCB were allocated dynamically, so nothing needs to be freed. */ configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) + portCLEAN_UP_TCB( pxTCB ); mtCOVERAGE_TEST_MARKER(); } } From 5362c7ac509f75f4aac2ce944e0ad478a8748109 Mon Sep 17 00:00:00 2001 From: "rudi ;-)" Date: Thu, 2 Mar 2017 23:41:18 +0100 Subject: [PATCH 32/57] ethernet: Fix typo in log message Merges #394 https://github.com/espressif/esp-idf/pull/394 --- components/ethernet/emac_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ethernet/emac_dev.c b/components/ethernet/emac_dev.c index ba61bb750..cde9790d3 100644 --- a/components/ethernet/emac_dev.c +++ b/components/ethernet/emac_dev.c @@ -86,7 +86,7 @@ void emac_reset(void) while (REG_GET_BIT(EMAC_DMABUSMODE_REG, EMAC_SW_RST) == 1) { //nothing to do ,if stop here,maybe emac have not clk input. - ESP_LOGI(TAG, "emac reseting ...."); + ESP_LOGI(TAG, "emac resetting ...."); } ESP_LOGI(TAG, "emac reset done"); From d8fda4855193d28eb81681a58b7ef7202d93d8aa Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 11:48:33 +0800 Subject: [PATCH 33/57] spi_flash: Split large SPI flash operations into parts, allowing preemption * Erase range operations allow preemption after each block or sector. * Write operations allow preemption every 8KB of data. * Reado operations allow preemption every 16KB of data. --- components/spi_flash/flash_ops.c | 128 +++++++++++--------- components/spi_flash/test/test_partitions.c | 68 +++++++++++ components/spi_flash/test/test_read_write.c | 4 +- 3 files changed, 138 insertions(+), 62 deletions(-) create mode 100644 components/spi_flash/test/test_partitions.c diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 324c02a3d..21a77a945 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -35,6 +35,12 @@ /* bytes erased by SPIEraseBlock() ROM function */ #define BLOCK_ERASE_SIZE 65536 +/* Limit number of bytes written/read in a single SPI operation, + as these operations disable all higher priority tasks from running. +*/ +#define MAX_WRITE_CHUNK 8192 +#define MAX_READ_CHUNK 16384 + #if CONFIG_SPI_FLASH_ENABLE_COUNTERS static const char* TAG = "spi_flash"; static spi_flash_counters_t s_flash_stats; @@ -94,19 +100,6 @@ size_t IRAM_ATTR spi_flash_get_chip_size() return g_rom_flashchip.chip_size; } -static SpiFlashOpResult IRAM_ATTR spi_flash_unlock() -{ - static bool unlocked = false; - if (!unlocked) { - SpiFlashOpResult rc = SPIUnlock(); - if (rc != SPI_FLASH_RESULT_OK) { - return rc; - } - unlocked = true; - } - return SPI_FLASH_RESULT_OK; -} - static inline void IRAM_ATTR spi_flash_guard_start() { if (s_flash_guard_ops && s_flash_guard_ops->start) { @@ -135,6 +128,21 @@ static inline void IRAM_ATTR spi_flash_guard_op_unlock() } } +static SpiFlashOpResult IRAM_ATTR spi_flash_unlock() +{ + static bool unlocked = false; + if (!unlocked) { + spi_flash_guard_start(); + SpiFlashOpResult rc = SPIUnlock(); + spi_flash_guard_end(); + if (rc != SPI_FLASH_RESULT_OK) { + return rc; + } + unlocked = true; + } + return SPI_FLASH_RESULT_OK; +} + esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec) { return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); @@ -155,11 +163,10 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) size_t end = start + size / SPI_FLASH_SEC_SIZE; const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE; COUNTER_START(); - spi_flash_guard_start(); - SpiFlashOpResult rc; - rc = spi_flash_unlock(); + SpiFlashOpResult rc = spi_flash_unlock(); if (rc == SPI_FLASH_RESULT_OK) { for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) { + spi_flash_guard_start(); if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) { rc = SPIEraseBlock(sector / sectors_per_block); sector += sectors_per_block; @@ -169,9 +176,9 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) ++sector; COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE); } + spi_flash_guard_end(); } } - spi_flash_guard_end(); COUNTER_STOP(erase); return spi_flash_translate_rc(rc); } @@ -202,9 +209,7 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) size_t mid_size = (size - left_size) & ~3U; size_t right_off = left_size + mid_size; size_t right_size = size - mid_size - left_size; - spi_flash_guard_start(); rc = spi_flash_unlock(); - spi_flash_guard_end(); if (rc != SPI_FLASH_RESULT_OK) { goto out; } @@ -220,43 +225,38 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size) COUNTER_ADD_BYTES(write, 4); } if (mid_size > 0) { - /* If src buffer is 4-byte aligned as well and is not in a region that - * requires cache access to be enabled, we can write it all at once. */ + /* If src buffer is 4-byte aligned as well and is not in a region that requires cache access to be enabled, we + * can write directly without buffering in RAM. */ #ifdef ESP_PLATFORM - bool in_dram = ((uintptr_t) srcc >= 0x3FFAE000 && - (uintptr_t) srcc < 0x40000000); + bool direct_write = ( (uintptr_t) srcc >= 0x3FFAE000 + && (uintptr_t) srcc < 0x40000000 + && ((uintptr_t) srcc + mid_off) % 4 == 0 ); #else - bool in_dram = true; + bool direct_write = true; #endif - if (in_dram && (((uintptr_t) srcc) + mid_off) % 4 == 0) { + while(mid_size > 0 && rc == SPI_FLASH_RESULT_OK) { + uint32_t write_buf[8]; + uint32_t write_size; + const uint32_t *write_src = (const uint32_t *) (srcc + mid_off); + if (direct_write) { + write_size = MIN(mid_size, MAX_WRITE_CHUNK); /* Write in chunks, to avoid starving other CPU/tasks */ + } else { + write_size = MIN(mid_size, sizeof(write_buf)); + memcpy(write_buf, write_src, write_size); + write_src = write_buf; + } spi_flash_guard_start(); - rc = SPIWrite(dst + mid_off, (const uint32_t *) (srcc + mid_off), mid_size); + rc = SPIWrite(dst + mid_off, write_src, write_size); spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { - goto out; - } - COUNTER_ADD_BYTES(write, mid_size); - } else { - /* - * Otherwise, unlike for read, we cannot manipulate data in the - * user-provided buffer, so we write in 32 byte blocks. - */ - while (mid_size > 0) { - uint32_t t[8]; - uint32_t write_size = MIN(mid_size, sizeof(t)); - memcpy(t, srcc + mid_off, write_size); - spi_flash_guard_start(); - rc = SPIWrite(dst + mid_off, t, write_size); - spi_flash_guard_end(); - if (rc != SPI_FLASH_RESULT_OK) { - goto out; - } - COUNTER_ADD_BYTES(write, write_size); - mid_size -= write_size; - mid_off += write_size; - } + COUNTER_ADD_BYTES(write, write_size); + mid_size -= write_size; + mid_off += write_size; + } + if (rc != SPI_FLASH_RESULT_OK) { + goto out; } } + if (right_size > 0) { uint32_t t = 0xffffffff; memcpy(&t, srcc + right_off, right_size); @@ -289,12 +289,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, } COUNTER_START(); - spi_flash_disable_interrupts_caches_and_other_cpu(); - SpiFlashOpResult rc; - spi_flash_guard_start(); - rc = spi_flash_unlock(); - spi_flash_guard_end(); - spi_flash_enable_interrupts_caches_and_other_cpu(); + SpiFlashOpResult rc = spi_flash_unlock(); if (rc == SPI_FLASH_RESULT_OK) { /* SPI_Encrypt_Write encrypts data in RAM as it writes, @@ -331,9 +326,9 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, memcpy(encrypt_buf, ssrc + i, 32); } - spi_flash_disable_interrupts_caches_and_other_cpu(); + spi_flash_guard_start(); rc = SPI_Encrypt_Write(row_addr, (uint32_t *)encrypt_buf, 32); - spi_flash_enable_interrupts_caches_and_other_cpu(); + spi_flash_guard_end(); if (rc != SPI_FLASH_RESULT_OK) { break; } @@ -341,6 +336,7 @@ esp_err_t IRAM_ATTR spi_flash_write_encrypted(size_t dest_addr, const void *src, bzero(encrypt_buf, sizeof(encrypt_buf)); } COUNTER_ADD_BYTES(write, size); + COUNTER_STOP(write); spi_flash_guard_op_lock(); spi_flash_mark_modified_region(dest_addr, size); @@ -402,9 +398,21 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size) size_t pad_right_off = (pad_right_src - src); size_t pad_right_size = (size - pad_right_off); if (mid_size > 0) { - rc = SPIRead(src + src_mid_off, (uint32_t *) (dstc + dst_mid_off), mid_size); - if (rc != SPI_FLASH_RESULT_OK) { - goto out; + uint32_t mid_remaining = mid_size; + uint32_t mid_read = 0; + while (mid_remaining > 0) { + uint32_t read_size = MIN(mid_remaining, MAX_READ_CHUNK); + rc = SPIRead(src + src_mid_off + mid_read, (uint32_t *) (dstc + dst_mid_off + mid_read), read_size); + if (rc != SPI_FLASH_RESULT_OK) { + goto out; + } + mid_remaining -= read_size; + mid_read += read_size; + if (mid_remaining > 0) { + /* Drop guard momentarily, allows other tasks to preempt */ + spi_flash_guard_end(); + spi_flash_guard_start(); + } } COUNTER_ADD_BYTES(read, mid_size); /* diff --git a/components/spi_flash/test/test_partitions.c b/components/spi_flash/test/test_partitions.c new file mode 100644 index 000000000..01dd5f445 --- /dev/null +++ b/components/spi_flash/test/test_partitions.c @@ -0,0 +1,68 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Test for spi_flash_{read,write}. + +#include +#include +#include +#include +#include + +#include +#include +#include + +TEST_CASE("Test erase partition", "[spi_flash]") +{ + const esp_partition_t *part = get_test_data_partition(); + +#if CONFIG_SPI_FLASH_ENABLE_COUNTERS + spi_flash_reset_counters(); +#endif + + // erase whole partition + ESP_ERROR_CHECK( esp_partition_erase_range(part, 0, part->size) ); + +#if CONFIG_SPI_FLASH_ENABLE_COUNTERS + spi_flash_dump_counters(); +#endif + + // put some dummy data on sector boundaries + const char *some_data = "abcdefghijklmn"; + for (int i = 0; i < part->size; i+= 4096) { + ESP_ERROR_CHECK( esp_partition_write(part, i, some_data, strlen(some_data)) ); + } + + // check it's there! + char buf[strlen(some_data)]; + for (int i = 0; i < part->size; i+= 4096) { + memset(buf, 0x00, sizeof(buf)); + ESP_ERROR_CHECK( esp_partition_read(part, i, buf, sizeof(buf)) ); + TEST_ASSERT_EQUAL_INT(0, strncmp(buf, some_data, sizeof(buf))); + } + + // erase the whole thing again + ESP_ERROR_CHECK( esp_partition_erase_range(part, 0, part->size) ); + + // check it's gone + for (int i = 0; i < part->size; i+= 4096) { + memset(buf, 0x00, sizeof(buf)); + ESP_ERROR_CHECK( esp_partition_read(part, i, buf, sizeof(buf)) ); + for (int i = 0; i < sizeof(buf); i++) { + TEST_ASSERT_EQUAL_HEX8(0xFF, buf[i]); + } + } + +} diff --git a/components/spi_flash/test/test_read_write.c b/components/spi_flash/test/test_read_write.c index aca485032..b9dc820b1 100644 --- a/components/spi_flash/test/test_read_write.c +++ b/components/spi_flash/test/test_read_write.c @@ -87,7 +87,7 @@ static void IRAM_ATTR test_read(int src_off, int dst_off, int len) TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_read", "[spi_flash_read]") +TEST_CASE("Test spi_flash_read", "[spi_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST @@ -165,7 +165,7 @@ static void IRAM_ATTR test_write(int dst_off, int src_off, int len) TEST_ASSERT_EQUAL_INT(cmp_or_dump(dst_buf, dst_gold, sizeof(dst_buf)), 0); } -TEST_CASE("Test spi_flash_write", "[spi_flash_write]") +TEST_CASE("Test spi_flash_write", "[spi_flash]") { setup_tests(); #if CONFIG_SPI_FLASH_MINIMAL_TEST From 8352e7e9ec4a525aa080e317566bf14a99af7d81 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 11:50:05 +0800 Subject: [PATCH 34/57] unit test: Measure test wall time with CCOUNT, so it includes time w/ interrupts off --- components/spi_flash/flash_ops.c | 2 +- tools/unit-test-app/components/unity/unity_platform.c | 10 +++++++--- tools/unit-test-app/main/app_main.c | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 21a77a945..86101ef04 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -491,7 +491,7 @@ static esp_err_t IRAM_ATTR spi_flash_translate_rc(SpiFlashOpResult rc) static inline void dump_counter(spi_flash_counter_t* counter, const char* name) { - ESP_LOGI(TAG, "%s count=%8d time=%8dms bytes=%8d\n", name, + ESP_LOGI(TAG, "%s count=%8d time=%8dus bytes=%8d\n", name, counter->count, counter->time, counter->bytes); } diff --git a/tools/unit-test-app/components/unity/unity_platform.c b/tools/unit-test-app/components/unity/unity_platform.c index 05e50a160..3f453326c 100644 --- a/tools/unit-test-app/components/unity/unity_platform.c +++ b/tools/unit-test-app/components/unity/unity_platform.c @@ -8,6 +8,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" +#include "soc/cpu.h" #define unity_printf ets_printf @@ -167,10 +168,13 @@ void unity_run_menu() int test_index = strtol(cmdline, NULL, 10); if (test_index >= 1 && test_index <= test_count) { - uint32_t start = esp_log_timestamp(); /* hacky way to get ms */ + uint32_t start; + RSR(CCOUNT, start); unity_run_single_test_by_index(test_index - 1); - uint32_t end = esp_log_timestamp(); - printf("Test ran in %dms\n", end - start); + uint32_t end; + RSR(CCOUNT, end); + uint32_t ms = (end - start) / (XT_CLOCK_FREQ / 1000); + printf("Test ran in %dms\n", ms); } } diff --git a/tools/unit-test-app/main/app_main.c b/tools/unit-test-app/main/app_main.c index b00034adf..58a195172 100644 --- a/tools/unit-test-app/main/app_main.c +++ b/tools/unit-test-app/main/app_main.c @@ -11,8 +11,10 @@ void unityTask(void *pvParameters) while(1); } -void app_main() +void app_main() { + // Note: if unpinning this task, change the way run times are calculated in + // unity_platform xTaskCreatePinnedToCore(unityTask, "unityTask", 4096, NULL, 5, NULL, 0); } From 099b5552c4a5596b28c595436c5d01651b6b8671 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 18:25:28 +0800 Subject: [PATCH 35/57] ci: Also run deployment steps for tags of form vX.Y (with optional -suffix) --- .gitlab-ci.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12714959b..cc04de8cf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -168,7 +168,8 @@ test_report: only: - master - triggers - - /^release\/v.*$/ + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ tags: - report variables: @@ -218,7 +219,8 @@ push_master_to_github: stage: deploy only: - master - - /^release\/v.*$/ + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ tags: - deploy when: on_success @@ -250,7 +252,8 @@ deploy_docs: stage: deploy only: - master - - /^release\/v.*$/ + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ - triggers tags: - deploy @@ -297,7 +300,8 @@ check_doc_links: when: on_success only: - master - - /^release\/v.*$/ + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ - triggers allow_failure: true From 818d1de771060309cb1f09740b9662662a40bac0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 18:39:28 +0800 Subject: [PATCH 36/57] ci: Swap github/gitlab submodules for release branches & tags also --- .gitlab-ci.yml | 12 +++++---- make/configure_ci_environment.sh | 35 +++++++++++++++++++++++++++ make/test_configure_ci_environment.sh | 34 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 make/configure_ci_environment.sh create mode 100755 make/test_configure_ci_environment.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cc04de8cf..2a2033684 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,10 +14,11 @@ before_script: - chmod 600 ~/.ssh/id_rsa - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config - # if testing master branch, use github wifi and bt libs. - # if testing other branches, use gitlab wifi and bt libs (as maybe changes aren't merged to master yet) - - test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-wifi-lib%${GITLAB_SSH_SERVER}/idf/esp32-wifi-lib%" .gitmodules - - test "${CI_BUILD_REF_NAME}" = "master" || sed -i "s%https://github.com/espressif/esp32-bt-lib%${GITLAB_SSH_SERVER}/idf/esp32-bt-lib%" .gitmodules + # Set IS_PRIVATE or IS_PUBLIC depending on if our branch is public or not + # + # (the same regular expressions are used to set these are used in 'only:' sections below + - source make/configure_ci_environment.sh + # fetch all submodules - git submodule update --init --recursive @@ -134,7 +135,7 @@ build_docs: - cd docs - doxygen # If not building master branch, and there are Doxygen warnings, print them and bail out - - test "${CI_BUILD_REF_NAME}" = "master" || test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false ) + - test -n $IS_PRIVATE && test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false ) - make gh-linkcheck - make html artifacts: @@ -160,6 +161,7 @@ test_build_system: variables: IDF_PATH: "$CI_PROJECT_DIR" script: + - ./make/test_configure_ci_environment.sh - ./make/test_build_system.sh test_report: diff --git a/make/configure_ci_environment.sh b/make/configure_ci_environment.sh new file mode 100644 index 000000000..bf2943dd1 --- /dev/null +++ b/make/configure_ci_environment.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Short script that is sourced in to the CI environment +# in .gitlab-ci.yml +# +# Sets IS_PUBLIC and IS_PRIVATE based on branch type +# +# Tweaks .gitmodules file for private builds + +[ -z $CI_BUILD_REF ] && echo "This internal script should only be run by a Gitlab CI runner." && exit 1 + +REF=$CI_BUILD_REF + +# Public branches are: +# release branches - start with release/ +# release tags - look like vXX.YY or vXX.YY.ZZ with an optional dash followed by anything on the end +# master branch +# +# These POSIX REs are equivalent to the REs in some "only:" sections of the gitlab-ci.yml file +# +if [[ $REF = "master" || $REF =~ ^release/v || $REF =~ ^v[0-9]+\.[0-9]+(\.[0-9]+)?(-|$) ]]; then + export IS_PUBLIC=1 +else + export IS_PRIVATE=1 +fi + +unset REF + +set -e + +if [[ $IS_PRIVATE ]]; then + # Redirect git submodules from public github to our private gitlab server + sed -i "s%https://github.com/espressif/esp32-wifi-lib%${GITLAB_SSH_SERVER}/idf/esp32-wifi-lib%" .gitmodules + sed -i "s%https://github.com/espressif/esp32-bt-lib%${GITLAB_SSH_SERVER}/idf/esp32-bt-lib%" .gitmodules +fi diff --git a/make/test_configure_ci_environment.sh b/make/test_configure_ci_environment.sh new file mode 100755 index 000000000..3ce0923e3 --- /dev/null +++ b/make/test_configure_ci_environment.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Short script to verify behaviour of configure_ci_environment.sh +# +# +cd $(dirname $0) # make dir + +touch .gitmodules # dummy file + +# $1 - branch name +# $2 - 1 if public, empty if private +function assert_branch_public() +{ + ( + CI_BUILD_REF=$1 + set -e + source ./configure_ci_environment.sh + [[ $IS_PUBLIC = $2 ]] || exit 1 + ) || ( echo "Expected $1 public=$2. Failing" && exit 1 ) +} + +assert_branch_public master 1 +assert_branch_public release/v3.0 1 +assert_branch_public release/invalid +assert_branch_public bugfix/invalid +assert_branch_public v1.0 1 +assert_branch_public v1.0.0 1 +assert_branch_public v50.50.50 1 +assert_branch_public v1.2-rc77 1 +assert_branch_public v1.2.3-rc1 1 +assert_branch_public v1.2.3invalid + +rm -f .gitmodules + From d96b8c317a6793abb82459b5f4b95623987b1752 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 22 Mar 2017 21:59:40 +0800 Subject: [PATCH 37/57] ci: allow passing Hub account or registry name from the environment --- .gitlab-ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12714959b..1a94f5af3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -23,7 +23,7 @@ before_script: build_template_app: stage: build - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env tags: - build @@ -57,7 +57,7 @@ build_template_app: stage: build tags: - build - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env variables: SDK_PATH: "$CI_PROJECT_DIR" @@ -127,7 +127,7 @@ build_examples: build_docs: stage: build - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env tags: - build_docs script: @@ -145,7 +145,7 @@ build_docs: test_nvs_on_host: stage: test - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env tags: - nvs_host_test script: @@ -154,7 +154,7 @@ test_nvs_on_host: test_build_system: stage: test - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env tags: - build_test variables: @@ -164,7 +164,7 @@ test_build_system: test_report: stage: test_report - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env only: - master - triggers @@ -222,7 +222,7 @@ push_master_to_github: tags: - deploy when: on_success - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env variables: GIT_STRATEGY: clone GITHUB_PUSH_REFS: refs/remotes/origin/release refs/remotes/origin/master @@ -254,7 +254,7 @@ deploy_docs: - triggers tags: - deploy - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env script: - mkdir -p ~/.ssh - chmod 700 ~/.ssh @@ -271,7 +271,7 @@ deploy_docs: check_doc_links: stage: test - image: espressif/esp32-ci-env + image: $CI_DOCKER_REGISTRY/esp32-ci-env tags: - check_doc_links only: From a3ce95e482a31d407e5a637c52d563ffc19d50d9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Mar 2017 16:46:48 +0800 Subject: [PATCH 38/57] build system: Add explicit DEBUG_FLAGS variable, pass to assembler also --- make/component_wrapper.mk | 2 +- make/project.mk | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/make/component_wrapper.mk b/make/component_wrapper.mk index 31e3c2765..87c05479a 100644 --- a/make/component_wrapper.mk +++ b/make/component_wrapper.mk @@ -165,7 +165,7 @@ $(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.cpp $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE $(1)/%.o: $$(COMPONENT_PATH)/$(1)/%.S $(COMMON_MAKEFILES) $(COMPONENT_MAKEFILE) | $(1) $$(summary) AS $$@ - $$(CC) $$(CPPFLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ + $$(CC) $$(CPPFLAGS) $$(DEBUG_FLAGS) $$(addprefix -I ,$$(COMPONENT_INCLUDES)) $$(addprefix -I ,$$(COMPONENT_EXTRA_INCLUDES)) -I$(1) -c $$< -o $$@ # CWD is build dir, create the build subdirectory if it doesn't exist $(1): diff --git a/make/project.mk b/make/project.mk index e1a23e96e..617e8aedd 100644 --- a/make/project.mk +++ b/make/project.mk @@ -241,13 +241,14 @@ OPTIMIZATION_FLAGS = -Og endif # Enable generation of debugging symbols -OPTIMIZATION_FLAGS += -ggdb +# (we generate even in Release mode, as this has no impact on final binary size.) +DEBUG_FLAGS ?= -ggdb # List of flags to pass to C compiler # If any flags are defined in application Makefile, add them at the end. CFLAGS := $(strip \ -std=gnu99 \ - $(OPTIMIZATION_FLAGS) \ + $(OPTIMIZATION_FLAGS) $(DEBUG_FLAGS) \ $(COMMON_FLAGS) \ $(COMMON_WARNING_FLAGS) -Wno-old-style-declaration \ $(CFLAGS) \ @@ -259,7 +260,7 @@ CXXFLAGS := $(strip \ -std=gnu++11 \ -fno-exceptions \ -fno-rtti \ - $(OPTIMIZATION_FLAGS) \ + $(OPTIMIZATION_FLAGS) $(DEBUG_FLAGS) \ $(COMMON_FLAGS) \ $(COMMON_WARNING_FLAGS) \ $(CXXFLAGS) \ From e88226c256a26170c41d1d607aa9dbe0163c554c Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 23 Mar 2017 10:41:14 +0800 Subject: [PATCH 39/57] idf_monitor: Use ANSI color codes for all output we inject into stderr --- tools/idf_monitor.py | 48 ++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/tools/idf_monitor.py b/tools/idf_monitor.py index 824a2f8e1..46d6e32bd 100644 --- a/tools/idf_monitor.py +++ b/tools/idf_monitor.py @@ -56,11 +56,20 @@ CTRL_T = '\x14' CTRL_RBRACKET = '\x1d' # Ctrl+] # ANSI terminal codes -ANSI_BLUE = '\033[0;34m' ANSI_RED = '\033[1;31m' ANSI_YELLOW = '\033[0;33m' ANSI_NORMAL = '\033[0m' +def color_print(message, color): + """ Print a message to stderr with colored highlighting """ + sys.stderr.write("%s%s%s\n" % (color, message, ANSI_NORMAL)) + +def yellow_print(message): + color_print(message, ANSI_YELLOW) + +def red_print(message): + color_print(message, ANSI_RED) + __version__ = "1.0" # Tags for tuples in queues @@ -288,7 +297,7 @@ class Monitor(object): if c == self.exit_key or c == self.menu_key: # send verbatim self.serial.write(codecs.encode(c)) elif c in [ CTRL_H, 'h', 'H', '?' ]: - sys.stderr.write(self.get_help_text()) + red_print(self.get_help_text()) elif c == CTRL_R: # Reset device via RTS self.serial.setRTS(True) time.sleep(0.2) @@ -298,7 +307,7 @@ class Monitor(object): elif c == CTRL_A: # Recompile & upload app only self.run_make("app-flash") else: - sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c))) + red_print('--- unknown menu character {} --'.format(key_description(c))) def get_help_text(self): return """ @@ -335,16 +344,15 @@ class Monitor(object): def prompt_next_action(self, reason): self.console.setup() # set up console to trap input characters try: - sys.stderr.write(ANSI_RED) - sys.stderr.write("--- {}\n".format(reason)) - sys.stderr.write("--- Press {} to exit monitor.\n" - .format(key_description(self.exit_key))) - sys.stderr.write("--- Press {} to run 'make flash'.\n" - .format(key_description(CTRL_F))) - sys.stderr.write("--- Press {} to run 'make app-flash'.\n" - .format(key_description(CTRL_A))) - sys.stderr.write("--- Press any other key to resume monitor (resets target).\n") - sys.stderr.write(ANSI_NORMAL) + red_print(""" +--- {} +--- Press {} to exit monitor. +--- Press {} to run 'make flash'. +--- Press {} to run 'make app-flash'. +--- Press any other key to resume monitor (resets target).""".format(reason, + key_description(self.exit_key), + key_description(CTRL_F), + key_description(CTRL_A))) k = CTRL_T # ignore CTRL-T here, so people can muscle-memory Ctrl-T Ctrl-F, etc. while k == CTRL_T: k = self.console.getkey() @@ -358,7 +366,7 @@ class Monitor(object): def run_make(self, target): with self: - sys.stderr.write("%s--- Running make %s...\n" % (ANSI_NORMAL, target)) + yellow_print("Running make %s..." % target) p = subprocess.Popen([self.make, target ]) try: @@ -374,7 +382,7 @@ class Monitor(object): "-pfia", "-e", self.elf_file, pc_addr], cwd=".") if not "?? ??:0" in translation: - sys.stderr.write(ANSI_YELLOW + translation + ANSI_NORMAL) + yellow_print(translation) def check_gdbstub_trigger(self, c): self._gdb_buffer = self._gdb_buffer[-6:] + c # keep the last 7 characters seen @@ -388,7 +396,7 @@ class Monitor(object): if chsum == calc_chsum: self.run_gdb() else: - sys.stderr.write("Malformed gdb message... calculated checksum %02x received %02x\n" % (chsum, calc_chsum)) + red_print("Malformed gdb message... calculated checksum %02x received %02x" % (chsum, calc_chsum)) def run_gdb(self): @@ -444,8 +452,8 @@ def main(): if args.port.startswith("/dev/tty."): args.port = args.port.replace("/dev/tty.", "/dev/cu.") - sys.stderr.write("WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched. ") - sys.stderr.write("Using %s instead...\n" % args.port) + yellow_print("--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.") + yellow_print("--- Using %s instead..." % args.port) serial_instance = serial.serial_for_url(args.port, args.baud, do_not_open=True) @@ -467,9 +475,9 @@ def main(): monitor = Monitor(serial_instance, args.elf_file.name, args.make, args.eol) - sys.stderr.write('--- idf_monitor on {p.name} {p.baudrate} ---\n'.format( + yellow_print('--- idf_monitor on {p.name} {p.baudrate} ---'.format( p=serial_instance)) - sys.stderr.write('--- Quit: {} | Menu: {} | Help: {} followed by {} ---\n'.format( + yellow_print('--- Quit: {} | Menu: {} | Help: {} followed by {} ---'.format( key_description(monitor.exit_key), key_description(monitor.menu_key), key_description(monitor.menu_key), From 6181c39f0515be575e56ec981916fadabcac9818 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Thu, 23 Mar 2017 11:33:46 +0800 Subject: [PATCH 40/57] Reset WIFI mac when wifi start and update wifi lib 1. reset wifi mac when wifi start 2. roll back rx hung workaround for beacon timeout 3. fix amsdu ap interface wrong issue 4. fix amsdu header parse error 5. fix amsdu flag wrong issue 6. PHY: V350, fix BT rssi bug 7. RTC: V225, fix bt will be not work when wifi is reset --- components/esp32/component.mk | 2 +- components/esp32/include/esp_phy_init.h | 3 +-- components/esp32/ld/esp32.common.ld | 1 + components/esp32/lib | 2 +- components/esp32/phy_init.c | 14 +++----------- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/components/esp32/component.mk b/components/esp32/component.mk index e7a88571f..ae0f331cd 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -3,7 +3,7 @@ # COMPONENT_SRCDIRS := . hwcrypto -LIBS := core rtc rtc_clk +LIBS := core rtc rtc_clk rtc_pm ifdef CONFIG_PHY_ENABLED # BT || WIFI LIBS += phy coexist endif diff --git a/components/esp32/include/esp_phy_init.h b/components/esp32/include/esp_phy_init.h index 9990957e2..347d8acac 100644 --- a/components/esp32/include/esp_phy_init.h +++ b/components/esp32/include/esp_phy_init.h @@ -232,12 +232,11 @@ esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_da * function. * @param mode Calibration mode (Full, partial, or no calibration) * @param[inout] calibration_data - * @param is_sleep WiFi wakes up from sleep or not * @return ESP_OK on success. * @return ESP_FAIL on fail. */ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep); + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data); /** * @brief De-initialize PHY and RF module diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index bc28e5ca9..30fa04d1c 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -84,6 +84,7 @@ SECTIONS *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *librtc_clk.a:(.literal .text .literal.* .text.*) + *librtc_pm.a:(.literal .text .literal.* .text.*) *libpp.a:pp.o(.literal .text .literal.* .text.*) *libpp.a:lmac.o(.literal .text .literal.* .text.*) *libpp.a:wdev.o(.literal .text .literal.* .text.*) diff --git a/components/esp32/lib b/components/esp32/lib index c88869b1a..a5287f930 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit c88869b1aca5a062d1ebc5e0199fd8720cb08710 +Subproject commit a5287f9300491b423ffd30ba83e4e1cec6f96125 diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 5fbeeb7c8..fb1158916 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -41,24 +41,16 @@ static const char* TAG = "phy_init"; /* Count value to indicate if there is peripheral that has initialized PHY and RF */ static int s_phy_rf_init_count = 0; -static bool s_mac_rst_flag = false; static _lock_t s_phy_rf_init_lock; esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, - esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data, bool is_sleep) + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) { assert((s_phy_rf_init_count <= 1) && (s_phy_rf_init_count >= 0)); _lock_acquire(&s_phy_rf_init_lock); if (s_phy_rf_init_count == 0) { - if (is_sleep == false) { - if (s_mac_rst_flag == false) { - s_mac_rst_flag = true; - REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST); - } - } // Enable WiFi peripheral clock SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN | DPORT_WIFI_CLK_RNG_EN); ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", @@ -289,7 +281,7 @@ void esp_phy_load_cal_and_init(void) calibration_mode = PHY_RF_CAL_FULL; } - esp_phy_rf_init(init_data, calibration_mode, cal_data, false); + esp_phy_rf_init(init_data, calibration_mode, cal_data); if (calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) { err = esp_phy_store_cal_data_to_nvs(cal_data); @@ -299,7 +291,7 @@ void esp_phy_load_cal_and_init(void) esp_phy_release_init_data(init_data); free(cal_data); // PHY maintains a copy of calibration data, so we can free this #else - esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, NULL, false); + esp_phy_rf_init(NULL, PHY_RF_CAL_NONE, NULL); #endif } From 61de08b0dd2ff7c67e0a09f11d07a5858a47e6cf Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Thu, 23 Mar 2017 17:47:48 +0800 Subject: [PATCH 41/57] tw11087: fix wifi restore exception 1. stop wifi before restore wifi --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index a5287f930..e5eebb6f3 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit a5287f9300491b423ffd30ba83e4e1cec6f96125 +Subproject commit e5eebb6f3a6a8f38a6914e6d6f378d48b397f4cd From 6ad0a157e39b17e4c3a81b73c9ee372ba530e4fc Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sun, 19 Mar 2017 23:59:19 +0800 Subject: [PATCH 42/57] driver/rtc: add APIs to enable/disable hold function --- components/driver/include/driver/rtc_io.h | 42 ++++++-- components/driver/rtc_module.c | 119 +++++++++++++--------- components/esp32/cpu_start.c | 2 +- components/esp32/deep_sleep.c | 2 +- 4 files changed, 110 insertions(+), 55 deletions(-) diff --git a/components/driver/include/driver/rtc_io.h b/components/driver/include/driver/rtc_io.h index 3a27a3476..65de941a4 100644 --- a/components/driver/include/driver/rtc_io.h +++ b/components/driver/include/driver/rtc_io.h @@ -38,7 +38,8 @@ typedef struct { uint32_t pulldown; /*!< Mask of pulldown enable */ uint32_t slpsel; /*!< If slpsel bit is set, slpie will be used as pad input enabled signal in sleep mode */ uint32_t slpie; /*!< Mask of input enable in sleep mode */ - uint32_t hold; /*!< Mask of hold_force bit for RTC IO in RTC_CNTL_HOLD_FORCE_REG */ + uint32_t hold; /*!< Mask of hold enable */ + uint32_t hold_force;/*!< Mask of hold_force bit for RTC IO in RTC_CNTL_HOLD_FORCE_REG */ int rtc_num; /*!< RTC IO number, or -1 if not an RTC GPIO */ } rtc_gpio_desc_t; @@ -192,15 +193,44 @@ esp_err_t rtc_gpio_pullup_dis(gpio_num_t gpio_num); esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num); /** - * @brief Disable "hold" signal for all RTC IOs + * @brief Enable hold function on an RTC IO pad * - * Each RTC pad has a "hold" input signal from the RTC controller. - * If hold signal is set, pad latches current values of input enable, + * Enabling HOLD function will cause the pad to latch current values of + * input enable, output enable, output value, function, drive strength values. + * This function is useful when going into light or deep sleep mode to prevent + * the pin configuration from changing. + * + * @param gpio_num GPIO number (e.g. GPIO_NUM_12) + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG GPIO is not an RTC IO + */ +esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num); + +/** + * @brief Disable hold function on an RTC IO pad + * + * Disabling hold function will allow the pad receive the values of + * input enable, output enable, output value, function, drive strength from + * RTC_IO peripheral. + * + * @param gpio_num GPIO number (e.g. GPIO_NUM_12) + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG GPIO is not an RTC IO + */ +esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num); + +/** + * @brief Disable force hold signal for all RTC IOs + * + * Each RTC pad has a "force hold" input signal from the RTC controller. + * If this signal is set, pad latches current values of input enable, * function, output enable, and other signals which come from the RTC mux. - * Hold signal is enabled before going into deep sleep for pins which + * Force hold signal is enabled before going into deep sleep for pins which * are used for EXT1 wakeup. */ -void rtc_gpio_unhold_all(); +void rtc_gpio_force_hold_dis_all(); #ifdef __cplusplus diff --git a/components/driver/rtc_module.c b/components/driver/rtc_module.c index 2a8204db9..60c5d6c89 100644 --- a/components/driver/rtc_module.c +++ b/components/driver/rtc_module.c @@ -42,46 +42,46 @@ static xSemaphoreHandle rtc_touch_sem = NULL; //Reg,Mux,Fun,IE,Up,Down,Rtc_number const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = { - {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, 11}, //0 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //1 - {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, RTC_CNTL_TOUCH_PAD2_HOLD_FORCE_M, 12}, //2 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //3 - {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, RTC_CNTL_TOUCH_PAD0_HOLD_FORCE_M, 10}, //4 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //5 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //6 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //7 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //8 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //9 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //10 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //11 - {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, RTC_CNTL_TOUCH_PAD5_HOLD_FORCE_M, 15}, //12 - {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, RTC_CNTL_TOUCH_PAD4_HOLD_FORCE_M, 14}, //13 - {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, RTC_CNTL_TOUCH_PAD6_HOLD_FORCE_M, 16}, //14 - {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, RTC_CNTL_TOUCH_PAD3_HOLD_FORCE_M, 13}, //15 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //16 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //17 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //18 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //19 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //20 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //21 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //22 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24 - {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 6}, //25 - {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 7}, //26 - {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, 17}, //27 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //30 - {0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //31 - {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, RTC_CNTL_X32P_HOLD_FORCE_M, 9}, //32 - {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, RTC_CNTL_X32N_HOLD_FORCE_M, 8}, //33 - {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, RTC_CNTL_ADC1_HOLD_FORCE_M, 4}, //34 - {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, RTC_CNTL_ADC2_HOLD_FORCE_M, 5}, //35 - {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, RTC_CNTL_SENSE1_HOLD_FORCE_M, 0}, //36 - {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, RTC_CNTL_SENSE2_HOLD_FORCE_M, 1}, //37 - {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, RTC_CNTL_SENSE3_HOLD_FORCE_M, 2}, //38 - {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, RTC_CNTL_SENSE4_HOLD_FORCE_M, 3}, //39 + {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, 11}, //0 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //1 + {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, RTC_IO_TOUCH_PAD2_HOLD_M, RTC_CNTL_TOUCH_PAD2_HOLD_FORCE_M, 12}, //2 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //3 + {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, RTC_IO_TOUCH_PAD0_HOLD_M, RTC_CNTL_TOUCH_PAD0_HOLD_FORCE_M, 10}, //4 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //5 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //6 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //7 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //8 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //9 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //10 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //11 + {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, RTC_IO_TOUCH_PAD5_HOLD_M, RTC_CNTL_TOUCH_PAD5_HOLD_FORCE_M, 15}, //12 + {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, RTC_IO_TOUCH_PAD4_HOLD_M, RTC_CNTL_TOUCH_PAD4_HOLD_FORCE_M, 14}, //13 + {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, RTC_IO_TOUCH_PAD6_HOLD_M, RTC_CNTL_TOUCH_PAD6_HOLD_FORCE_M, 16}, //14 + {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, RTC_IO_TOUCH_PAD3_HOLD_M, RTC_CNTL_TOUCH_PAD3_HOLD_FORCE_M, 13}, //15 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //16 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //17 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //18 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //19 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //20 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //21 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //22 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24 + {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 6}, //25 + {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, 7}, //26 + {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, 17}, //27 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //30 + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //31 + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, RTC_IO_X32P_HOLD_M, RTC_CNTL_X32P_HOLD_FORCE_M, 9}, //32 + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, RTC_IO_X32N_HOLD_M, RTC_CNTL_X32N_HOLD_FORCE_M, 8}, //33 + {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC1_HOLD_FORCE_M, 4}, //34 + {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC2_HOLD_FORCE_M, 5}, //35 + {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE1_HOLD_FORCE_M, 0}, //36 + {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE2_HOLD_FORCE_M, 1}, //37 + {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE3_HOLD_FORCE_M, 2}, //38 + {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE4_HOLD_FORCE_M, 3}, //39 }; /*--------------------------------------------------------------- @@ -207,7 +207,7 @@ esp_err_t rtc_gpio_pullup_en(gpio_num_t gpio_num) { //this is a digital pad if (rtc_gpio_desc[gpio_num].pullup == 0) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } //this is a rtc pad @@ -222,7 +222,7 @@ esp_err_t rtc_gpio_pulldown_en(gpio_num_t gpio_num) { //this is a digital pad if (rtc_gpio_desc[gpio_num].pulldown == 0) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } //this is a rtc pad @@ -237,7 +237,7 @@ esp_err_t rtc_gpio_pullup_dis(gpio_num_t gpio_num) { //this is a digital pad if ( rtc_gpio_desc[gpio_num].pullup == 0 ) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } //this is a rtc pad @@ -252,7 +252,7 @@ esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num) { //this is a digital pad if (rtc_gpio_desc[gpio_num].pulldown == 0) { - return ESP_FAIL; + return ESP_ERR_INVALID_ARG; } //this is a rtc pad @@ -263,12 +263,37 @@ esp_err_t rtc_gpio_pulldown_dis(gpio_num_t gpio_num) return ESP_OK; } -void rtc_gpio_unhold_all() +esp_err_t rtc_gpio_hold_en(gpio_num_t gpio_num) +{ + // check if an RTC IO + if (rtc_gpio_desc[gpio_num].pullup == 0) { + return ESP_ERR_INVALID_ARG; + } + portENTER_CRITICAL(&rtc_spinlock); + SET_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].hold); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + +esp_err_t rtc_gpio_hold_dis(gpio_num_t gpio_num) +{ + // check if an RTC IO + if (rtc_gpio_desc[gpio_num].pullup == 0) { + return ESP_ERR_INVALID_ARG; + } + portENTER_CRITICAL(&rtc_spinlock); + CLEAR_PERI_REG_MASK(rtc_gpio_desc[gpio_num].reg, rtc_gpio_desc[gpio_num].hold); + portEXIT_CRITICAL(&rtc_spinlock); + return ESP_OK; +} + + +void rtc_gpio_force_hold_dis_all() { for (int gpio = 0; gpio < GPIO_PIN_COUNT; ++gpio) { const rtc_gpio_desc_t* desc = &rtc_gpio_desc[gpio]; - if (desc->hold != 0) { - REG_CLR_BIT(RTC_CNTL_HOLD_FORCE_REG, desc->hold); + if (desc->hold_force != 0) { + REG_CLR_BIT(RTC_CNTL_HOLD_FORCE_REG, desc->hold_force); } } } diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 2dbfffd5a..495a17803 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -185,7 +185,7 @@ void start_cpu0_default(void) #if CONFIG_BROWNOUT_DET esp_brownout_init(); #endif - rtc_gpio_unhold_all(); + rtc_gpio_force_hold_dis_all(); esp_setup_time_syscalls(); esp_vfs_dev_uart_register(); esp_reent_init(_GLOBAL_REENT); diff --git a/components/esp32/deep_sleep.c b/components/esp32/deep_sleep.c index 55e92a05e..d1666affe 100644 --- a/components/esp32/deep_sleep.c +++ b/components/esp32/deep_sleep.c @@ -291,7 +291,7 @@ static void ext1_wakeup_prepare() REG_SET_BIT(desc->reg, desc->ie); REG_CLR_BIT(desc->reg, desc->pulldown); REG_CLR_BIT(desc->reg, desc->pullup); - REG_SET_BIT(RTC_CNTL_HOLD_FORCE_REG, desc->hold); + REG_SET_BIT(RTC_CNTL_HOLD_FORCE_REG, desc->hold_force); } // Keep track of pins which are processed to bail out early rtc_gpio_mask &= ~BIT(rtc_pin); From 573cc7d36ff3e4f43bb6f498228cbbb735f9b627 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Sat, 18 Mar 2017 17:27:19 +0800 Subject: [PATCH 43/57] esp32: make soc header compatible with assembler --- components/esp32/include/soc/soc.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 1b3e35dd4..9b0c82fc1 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -15,7 +15,9 @@ #ifndef _ESP32_SOC_H_ #define _ESP32_SOC_H_ +#ifndef __ASSEMBLER__ #include +#endif //Register Bits{{ #define BIT31 0x80000000 @@ -59,7 +61,11 @@ #define ETS_UNCACHED_ADDR(addr) (addr) #define ETS_CACHED_ADDR(addr) (addr) +#ifndef __ASSEMBLER__ #define BIT(nr) (1UL << (nr)) +#else +#define BIT(nr) (1 << (nr)) +#endif //__ASSEMBLER__ //write value to register #define REG_WRITE(_r, _v) (*(volatile uint32_t *)(_r)) = (_v) From 0e31eb458e649b66277e3705f603216740e845dd Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 24 Mar 2017 10:41:45 +0800 Subject: [PATCH 44/57] esp32: Move heap_alloc_caps to IRAM Rest of malloc() path was already in IRAM --- components/esp32/ld/esp32.common.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index bc28e5ca9..d4e138eac 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -81,6 +81,7 @@ SECTIONS *libfreertos.a:(.literal .text .literal.* .text.*) *libesp32.a:panic.o(.literal .text .literal.* .text.*) *libesp32.a:core_dump.o(.literal .text .literal.* .text.*) + *libesp32.a:heap_alloc_caps.o(.literal .text .literal.* .text.*) *libphy.a:(.literal .text .literal.* .text.*) *librtc.a:(.literal .text .literal.* .text.*) *librtc_clk.a:(.literal .text .literal.* .text.*) From a30c98c1a2bfc4525b0207fbf118e3d12065291e Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Fri, 24 Mar 2017 08:41:34 +0800 Subject: [PATCH 45/57] fix compile bug 1. split some unused rtc functions that calls phy function 2. make check bt idle more safe when reset wifi mac --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index e5eebb6f3..5c98c5a8b 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit e5eebb6f3a6a8f38a6914e6d6f378d48b397f4cd +Subproject commit 5c98c5a8b93dbf181849b40c6d6cd164a52bfc4c From f5aee6a6e66ced951871d0a0de456102dddde884 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Mar 2017 11:17:19 +0800 Subject: [PATCH 46/57] windows config: Update Windows setup script, pre-installed image, instructions. Add notes about MSYS2 package mirrors & HTTP proxies for users in China. Closes #260 https://github.com/espressif/esp-idf/issues/260 Closes #281 https://github.com/espressif/esp-idf/issues/281 Closes #200 https://github.com/espressif/esp-idf/issues/200 Closes #430 https://github.com/espressif/esp-idf/pull/430 Accomplishes similar goals to #264 https://github.com/espressif/esp-idf/pull/264 --- docs/windows-setup-scratch.rst | 65 +++++++++++++++++++ docs/windows-setup.rst | 30 ++------- .../windows/windows_install_prerequisites.sh | 52 ++++++++++----- 3 files changed, 107 insertions(+), 40 deletions(-) create mode 100644 docs/windows-setup-scratch.rst mode change 100755 => 100644 tools/windows/windows_install_prerequisites.sh diff --git a/docs/windows-setup-scratch.rst b/docs/windows-setup-scratch.rst new file mode 100644 index 000000000..2037a21da --- /dev/null +++ b/docs/windows-setup-scratch.rst @@ -0,0 +1,65 @@ +Set up Windows Toolchain from Scratch +************************************* + +This is an **optional alternative to the normal Windows Guide**. + +:doc:`See the main Windows setup page for the quickest and simplest Windows setup guide `. + +Setting up the environment gives you some more control over the process, and also provides the information for advanced users to customise the install. The pre-built environment has been prepared by following these steps. + +Configure toolchain & environment from scratch +============================================== + +This process involves installing MSYS2_, then installing the MSYS2_ and Python packages which ESP-IDF uses, and finally downloading and installing the Xtensa toolchain. + +* Navigate to the MSYS2_ installer page and download the ``msys2-i686-xxxxxxx.exe`` installer executable (we only support a 32-bit MSYS environment, it works on both 32-bit and 64-bit Windows.) At time of writing, the latest installer is ``msys2-i686-20161025.exe``. + +* Run through the installer steps. **Uncheck the "Run MSYS2 32-bit now" checkbox at the end.** + +* Once the installer exits, open Start Menu and find "MSYS2 MinGW 32-bit" to run the terminal. + + *(Why launch this different terminal? MSYS2 has the concept of different kinds of environments. The default "MSYS" environment is Cygwin-like and uses a translation layer for all Windows API calls. We need the "MinGW" environment in order to have a native Python which supports COM ports.)* + +* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't got a local copy of the ESP-IDF yet, that's OK - you can just download that one file in Raw format from here: :idf_raw:`tools/windows/windows_install_prerequisites.sh`. Save it somewhere on your computer. + +* Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: ``C:/Users/myuser/Downloads/windows_install_prerequisites.sh``. You can read the script beforehand to check what it does. + +* The ``windows_install_prerequisites.sh`` script will download and install packages for ESP-IDF support, and the ESP32 toolchain. + +* During the initial update step, MSYS may update itself into a state where it can no longer operate. You may see errors like the following:: + + *** fatal error - cygheap base mismatch detected - 0x612E5408/0x612E4408. This problem is probably due to using incompatible versions of the cygwin DLL. + + If you see errors like this, close the terminal window entirely (terminating the processes running there) and then re-open a new terminal. Re-run ``windows_install_prerequisites.sh`` (tip: use the up arrow key to see the last run command). The update process will resume after this step. + + +MSYS2 Mirrors in China +~~~~~~~~~~~~~~~~~~~~~~ + +There are some (unofficial) MSYS2 mirrors inside China, which substantially improves download speeds inside China. + +To add these mirrors, edit the following two MSYS2 mirrorlist files before running the setup script. The mirrorlist files can be found in the ``/etc/pacman.d`` directory (ie ``c:\msys2\etc\pacman.d``). + +Add these lines at the top of ``mirrorlist.mingw32``:: + + Server = http://mirrors.ustc.edu.cn/msys2/mingw/i686/ + Server = http://mirror.bit.edu.cn/msys2/REPOS/MINGW/i686 + +Add these lines at the top of ``mirrorlist.msys``:: + + Server = http://mirrors.ustc.edu.cn/msys2/msys/$arch + Server = http://mirror.bit.edu.cn/msys2/REPOS/MSYS2/$arch + + +HTTP Proxy +~~~~~~~~~~ + +You can enable an HTTP proxy for MSYS and PIP downloads by setting the ``http_proxy`` variable in the terminal before running the setup script:: + + export http_proxy='http://http.proxy.server:PORT' + +Or with credentials:: + + export http_proxy='http://user:password@http.proxy.server:PORT' + +Add this line to ``/etc/profile`` in the MSYS directory in order to permanently enable the proxy when using MSYS. diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index 996eacee5..9499b88b5 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -4,34 +4,18 @@ Set up of Toolchain for Windows Step 1: Quick Steps =================== -Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide. - You don't need to use this environment all the time (you can use Eclipse_ or some other front-end), but it runs behind the scenes. +Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide this. You don't need to use this environment all the time (you can use Eclipse_ or some other front-end), but it runs behind the scenes. The quick setup is to download the Windows all-in-one toolchain & MSYS zip file from dl.espressif.com: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20170111.zip - -Unzip the zip file to C:\ and it will create an "msys32" directory with a pre-prepared environment. +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20170321.zip +Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an "msys32" directory with a pre-prepared environment. Alternative Step 1: Configure toolchain & environment from scratch ================================================================== -As an alternative to getting a pre-prepared environment, you can set up the environment from scratch: - -* Navigate to the MSYS2_ installer page and download the ``msys2-i686-xxxxxxx.exe`` installer executable (we only support a 32-bit MSYS environment, it works on both 32-bit and 64-bit Windows.) - -* Run through the installer steps, and accept the "Run MSYS2 now" option at the end. A window will open with a MSYS2 terminal. - -* The ESP-IDF repository on github contains a script in the tools directory titled ``windows_install_prerequisites.sh``. If you haven't downloaded the ESP-IDF yet, that's OK - you can just download that one file in Raw format from here: :idf_raw:`tools/windows/windows_install_prerequisites.sh`. Save it somewhere on your computer. - -* Type the path to the shell script into the MSYS2 terminal window. You can type it as a normal Windows path, but use forward-slashes instead of back-slashes. ie: ``C:/Users/myuser/Downloads/windows_install_prerequisites.sh``. You can read the script beforehand to check what it does. - -* If you use the 201602 MSYS2 installer, the first time you run ``windows_install_prerequisites.sh`` it will update the MSYS2 core system. At the end of this update, you will be prompted to close the MSYS2 terminal and re-open. When you re-open after the update, re-run ``windows_install_prerequisites.sh``. The next version of MSYS2 (after 201602) will not need this interim step. - -* The ``windows_install_prerequisites.sh`` script will download and install packages for ESP-IDF support, and the ESP32 toolchain. - -Note: You may encounter a bug where svchost.exe uses 100% CPU in Windows after setup is finished, resulting in the ESP-IDF building very slowly. Terminating svchost.exe or restarting Windows will solve this problem. +Rather than use the pre-prepared environment, you can :doc:`alternatively follow this guide to set up the MSYS2 environment from scratch `. Another Alternative Step 1: Just download a toolchain ===================================================== @@ -40,14 +24,14 @@ If you already have an MSYS2 install or want to do things differently, you can d https://dl.espressif.com/dl/xtensa-esp32-elf-win32-1.22.0-61-gab8375a-5.2.0.zip -If you followed one of the above options for Step 1, you won't need this download. +**If you followed one of the above options for Step 1, you already have the toolchain and you won't need this download.** -Important: Just having this toolchain is *not enough* to use ESP-IDF on Windows. You will need GNU make, bash, and sed at minimum. The above environments provide all this, plus a host compiler (required for menuconfig support). +**Important**: Just having this toolchain is *not enough* to use ESP-IDF on Windows. You will need GNU make, bash, and sed at minimum. The above environments provide all this, plus a host compiler (required for menuconfig support). Step 2: Getting the esp-idf repository from github ================================================== -Open an MSYS2 terminal window by running ``C:\msys32\msys2_shell.cmd``. The environment in this window is a bash shell. +Open an MSYS2 terminal window by running ``C:\msys32\mingw32.exe``. The environment in this window is a bash shell. Change to the directory you want to clone the SDK into by typing a command like this one: ``cd "C:/path/to/dir"`` (note the forward-slashes in the path). Then type ``git clone --recursive https://github.com/espressif/esp-idf.git`` diff --git a/tools/windows/windows_install_prerequisites.sh b/tools/windows/windows_install_prerequisites.sh old mode 100755 new mode 100644 index e8b3b9eb2..1b3f39059 --- a/tools/windows/windows_install_prerequisites.sh +++ b/tools/windows/windows_install_prerequisites.sh @@ -1,7 +1,11 @@ #!/bin/bash # -# Setup script to configure an MSYS2 environment for Espressif IoT Development Framework (ESP-IDF). -# See docs/windows-setup.rst for details. +# Setup script to configure an MSYS2 environment for ESP-IDF. +# +# Use of this script is optional, there is also a prebuilt MSYS2 environment available +# which can be downloaded and used as-is. +# +# See http://esp-idf.readthedocs.io/en/latest/windows-setup.html for full details. if [ "$OSTYPE" != "msys" ]; then echo "This setup script expects to be run from an MSYS2 environment on Windows." @@ -11,6 +15,12 @@ if ! [ -x /bin/pacman ]; then echo "This setup script expects to use the pacman package manager from MSYS2." exit 1 fi +if [ "$MSYSTEM" != "MINGW32" ]; then + echo "This setup script must be started from the 'MSYS2 MinGW 32-bit' start menu shortcut" + echo "OR by running `cygpath -w /mingw32.exe`" + echo "(The current MSYSTEM mode is $MSYSTEM but it expects it to be MINGW32)" + exit 1 +fi # if update-core still exists, run it to get the latest core MSYS2 system # (which no longer needs or includes update-core!) @@ -21,16 +31,16 @@ fi set -e -pacman --noconfirm -Syu +pacman --noconfirm -Syu # This step may require the terminal to be closed and restarted -pacman --noconfirm -S gettext-devel gcc git make ncurses-devel flex bison gperf vim mingw-w64-i686-python2-pip unzip +pacman --noconfirm -S --needed gettext-devel gcc git make ncurses-devel flex bison gperf vim mingw-w64-i686-python2-pip unzip winpty python -m pip install --upgrade pip pip install pyserial -# TODO: automatically download precompiled toolchain, unpack at /opt/xtensa-esp32-elf/ -TOOLCHAIN_ZIP=xtensa-esp32-elf-win32-1.22.0-59.zip +# Automatically download precompiled toolchain, unpack at /opt/xtensa-esp32-elf/ +TOOLCHAIN_ZIP=xtensa-esp32-elf-win32-1.22.0-61-gab8375a-5.2.0.zip echo "Downloading precompiled toolchain ${TOOLCHAIN_ZIP}..." cd ~ curl -LO --retry 10 http://dl.espressif.com/dl/${TOOLCHAIN_ZIP} @@ -39,6 +49,8 @@ unzip ~/${TOOLCHAIN_ZIP} rm ~/${TOOLCHAIN_ZIP} cat > /etc/profile.d/esp32_toolchain.sh << EOF +# This file was created by ESP-IDF windows_install_prerequisites.sh +# and will be overwritten if that script is run again. export PATH="$PATH:/opt/xtensa-esp32-elf/bin" EOF @@ -46,15 +58,21 @@ EOF pacman --noconfirm -R unzip pacman --noconfirm -Scc -echo "************************************************" -echo "MSYS2 environment is now ready to use ESP-IDF." -echo "Run 'source /etc/profile' to add the toolchain to" -echo "your path. Execute 'msys_shell.cmd' to launch an" -echo "MSYS terminal." -echo -echo "Once ESP-IDF is downloaded/checked out, set the" -echo "environment variable IDF_PATH in /etc/profile to" -echo "point to the directory." -echo "************************************************" -echo +cat << EOF +************************************************ +MSYS2 environment is now ready to use ESP-IDF. +1) Run 'source /etc/profile' to add the toolchain to +your path in this terminal. This command produces no output. +You only need to do this once, future terminals do this +automatically when opened. + +2) After ESP-IDF is set up (see setup guide), edit the file +`cygpath -w /etc/profile` +and add a line to set the variable IDF_PATH so it points to the +IDF directory, ie: + +export IDF_PATH=/c/path/to/esp-idf/directory + +************************************************ +EOF From aceb08f93886babdc32f326be5a020db91180c1d Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 21 Mar 2017 15:37:17 +0800 Subject: [PATCH 47/57] docs: Mention the 'examples' dir in the setup docs --- docs/linux-setup.rst | 3 +++ docs/macos-setup.rst | 3 +++ docs/windows-setup.rst | 3 +++ 3 files changed, 9 insertions(+) diff --git a/docs/linux-setup.rst b/docs/linux-setup.rst index d3b8597cd..bfcdf22f0 100644 --- a/docs/linux-setup.rst +++ b/docs/linux-setup.rst @@ -142,6 +142,9 @@ The easiest way to start a project is to download the template project from GitH This will download ``esp-idf-template`` project into ``~/esp/myapp`` directory. +**IMPORTANT:** The esp-idf build system does not support spaces in paths to esp-idf or to projects. + +You can also find a range of example projects under the "examples" directory in IDF. These example project directories can be copied to outside IDF in order to begin your own projects. Step 4: Building and flashing the application ============================================= diff --git a/docs/macos-setup.rst b/docs/macos-setup.rst index e8f8257b2..33164f248 100644 --- a/docs/macos-setup.rst +++ b/docs/macos-setup.rst @@ -130,6 +130,9 @@ This will download ``esp-idf-template`` project into ``~/esp/myapp`` directory. **IMPORTANT:** The esp-idf build system does not support spaces in paths to esp-idf or to projects. +You can also find a range of example projects under the "examples" directory in IDF. These example project directories can be copied to outside IDF in order to begin your own projects. + + Step 4: Building and flashing the application ============================================= diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index 9499b88b5..16b46732a 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -50,6 +50,9 @@ The process is the same as for checking out the ESP-IDF from github. Change to t **IMPORTANT:** The esp-idf build system does not support spaces in paths to esp-idf or to projects. +You can also find a range of example projects under the "examples" directory in IDF. These example project directories can be copied to outside IDF in order to begin your own projects. + + Step 4: Configuring the project =============================== From a6e4e895920d2bae3cbe34c61b89ee42770d5fa8 Mon Sep 17 00:00:00 2001 From: Dmitry Yakovlev Date: Mon, 9 Jan 2017 07:38:20 +0300 Subject: [PATCH 48/57] ulp: add build system integration and example --- components/esp32/include/soc/soc_ulp.h | 46 ++ components/ulp/Makefile.projbuild | 8 + components/ulp/README.rst | 11 +- components/ulp/component_ulp_common.mk | 96 +++ components/ulp/esp32ulp_mapgen.py | 54 ++ components/ulp/include/esp32/ulp.h | 28 + components/ulp/ld/esp32.ulp.ld | 35 + components/ulp/ulp.c | 281 ++----- components/ulp/ulp_macro.c | 262 +++++++ docs/ulp.rst | 162 ++++- docs/ulp_instruction_set.rst | 768 ++++++++++++++++++++ docs/ulp_macros.rst | 1 + examples/system/ulp/Makefile | 9 + examples/system/ulp/README.md | 50 ++ examples/system/ulp/main/component.mk | 25 + examples/system/ulp/main/ulp/pulse_cnt.S | 135 ++++ examples/system/ulp/main/ulp_example_main.c | 106 +++ examples/system/ulp/sdkconfig.defaults | 11 + 18 files changed, 1849 insertions(+), 239 deletions(-) create mode 100644 components/esp32/include/soc/soc_ulp.h create mode 100644 components/ulp/Makefile.projbuild create mode 100644 components/ulp/component_ulp_common.mk create mode 100755 components/ulp/esp32ulp_mapgen.py create mode 100644 components/ulp/ld/esp32.ulp.ld create mode 100644 components/ulp/ulp_macro.c create mode 100755 docs/ulp_instruction_set.rst create mode 100644 docs/ulp_macros.rst create mode 100644 examples/system/ulp/Makefile create mode 100644 examples/system/ulp/README.md create mode 100644 examples/system/ulp/main/component.mk create mode 100644 examples/system/ulp/main/ulp/pulse_cnt.S create mode 100644 examples/system/ulp/main/ulp_example_main.c create mode 100644 examples/system/ulp/sdkconfig.defaults diff --git a/components/esp32/include/soc/soc_ulp.h b/components/esp32/include/soc/soc_ulp.h new file mode 100644 index 000000000..ad1f4f50c --- /dev/null +++ b/components/esp32/include/soc/soc_ulp.h @@ -0,0 +1,46 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +// This file contains various convenience macros to be used in ULP programs. + +// Helper macros to calculate bit field width from mask, using the preprocessor. +// Used later in READ_RTC_FIELD and WRITE_RTC_FIELD. +#define IS_BIT_SET(m, i) (((m) >> (i)) & 1) +#define MASK_TO_WIDTH_HELPER1(m, i) IS_BIT_SET(m, i) +#define MASK_TO_WIDTH_HELPER2(m, i) (MASK_TO_WIDTH_HELPER1(m, i) + MASK_TO_WIDTH_HELPER1(m, i + 1)) +#define MASK_TO_WIDTH_HELPER4(m, i) (MASK_TO_WIDTH_HELPER2(m, i) + MASK_TO_WIDTH_HELPER2(m, i + 2)) +#define MASK_TO_WIDTH_HELPER8(m, i) (MASK_TO_WIDTH_HELPER4(m, i) + MASK_TO_WIDTH_HELPER4(m, i + 4)) +#define MASK_TO_WIDTH_HELPER16(m, i) (MASK_TO_WIDTH_HELPER8(m, i) + MASK_TO_WIDTH_HELPER8(m, i + 8)) +#define MASK_TO_WIDTH_HELPER32(m, i) (MASK_TO_WIDTH_HELPER16(m, i) + MASK_TO_WIDTH_HELPER16(m, i + 16)) + +// Peripheral register access macros, build around REG_RD and REG_WR instructions. +// Registers defined in rtc_cntl_reg.h, rtc_io_reg.h, and sens_reg.h are usable with these macros. + +// Read from rtc_reg[low_bit + bit_width - 1 : low_bit] into R0, bit_width <= 16 +#define READ_RTC_REG(rtc_reg, low_bit, bit_width) \ + REG_RD (((rtc_reg) - DR_REG_RTCCNTL_BASE) / 4), ((low_bit) + (bit_width) - 1), (low_bit) + +// Write immediate value into rtc_reg[low_bit + bit_width - 1 : low_bit], bit_width <= 8 +#define WRITE_RTC_REG(rtc_reg, low_bit, bit_width, value) \ + REG_WR (((rtc_reg) - DR_REG_RTCCNTL_BASE) / 4), ((low_bit) + (bit_width) - 1), (low_bit), ((value) & 0xff) + +// Read from a field in rtc_reg into R0, up to 16 bits +#define READ_RTC_FIELD(rtc_reg, field) \ + READ_RTC_REG(rtc_reg, field ## _S, MASK_TO_WIDTH_HELPER16(field ## _V, 0)) + +// Write immediate value into a field in rtc_reg, up to 8 bits +#define WRITE_RTC_FIELD(rtc_reg, field, value) \ + WRITE_RTC_REG(rtc_reg, field ## _S, MASK_TO_WIDTH_HELPER8(field ## _V, 0), ((value) & field ## _V)) + diff --git a/components/ulp/Makefile.projbuild b/components/ulp/Makefile.projbuild new file mode 100644 index 000000000..026d64452 --- /dev/null +++ b/components/ulp/Makefile.projbuild @@ -0,0 +1,8 @@ +ULP_BINUTILS_PREFIX ?= esp32ulp-elf- +export ULP_AS := $(ULP_BINUTILS_PREFIX)as +export ULP_LD := $(ULP_BINUTILS_PREFIX)ld +export ULP_OBJCOPY := $(ULP_BINUTILS_PREFIX)objcopy +export ULP_OBJDUMP := $(ULP_BINUTILS_PREFIX)objdump +export ULP_NM := $(ULP_BINUTILS_PREFIX)nm +export ULP_LD_TEMPLATE := $(IDF_PATH)/components/ulp/ld/esp32.ulp.ld +export ULP_MAP_GEN := $(IDF_PATH)/components/ulp/esp32ulp_mapgen.py diff --git a/components/ulp/README.rst b/components/ulp/README.rst index 875a01ef8..af1a748f8 100644 --- a/components/ulp/README.rst +++ b/components/ulp/README.rst @@ -1,12 +1,7 @@ -ULP coprocessor programming -=========================== +Programming ULP coprocessor using C macros +========================================== -.. warning:: ULP coprocessor programming approach described here is experimental. It is probable that once binutils support for ULP is done, this preprocessor-based approach may be deprecated. We welcome discussion about and contributions to ULP programming tools. - -ULP coprocessor is a simple FSM which is designed to perform measurements using ADC, temperature sensor, and external I2C sensors, while main processors are in deep sleep mode. ULP coprocessor can access RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general purpose 16-bit registers. - -ULP coprocessor doesn't have a dedicated binutils port yet. Programming ULP coprocessor is possible by embedding assembly-like macros into an ESP32 application. -Here is an example how this can be done:: +In addition to the existing binutils port for the ESP32 ULP coprocessor, it is possible to generate programs for the ULP by embedding assembly-like macros into an ESP32 application. Here is an example how this can be done:: const ulp_insn_t program[] = { I_MOVI(R3, 16), // R3 <- 16 diff --git a/components/ulp/component_ulp_common.mk b/components/ulp/component_ulp_common.mk new file mode 100644 index 000000000..e6b5a2819 --- /dev/null +++ b/components/ulp/component_ulp_common.mk @@ -0,0 +1,96 @@ +# Extra make rules for components containing ULP coprocessor code. +# +# ULP program(s) gets built and linked into the application. +# Steps taken here are explained in docs/ulp.rst + +# Define names for files generated at different stages +ULP_ELF := $(ULP_APP_NAME).elf +ULP_MAP := $(ULP_ELF:.elf=.map) +ULP_SYM := $(ULP_ELF:.elf=.sym) +ULP_BIN := $(ULP_ELF:.elf=.bin) +ULP_EXPORTS_LD := $(ULP_ELF:.elf=.ld) +ULP_EXPORTS_HEADER := $(ULP_ELF:.elf=.h) +ULP_LD_SCRIPT := $(ULP_ELF:.elf=.common.ld) + +ULP_OBJECTS := $(notdir $(ULP_S_SOURCES:.S=.ulp.o)) +ULP_DEP := $(notdir $(ULP_S_SOURCES:.S=.ulp.d)) $(ULP_LD_SCRIPT:.ld=.d) +ULP_PREPROCESSED := $(notdir $(ULP_S_SOURCES:.S=.ulp.pS)) +ULP_LISTINGS := $(notdir $(ULP_S_SOURCES:.S=.ulp.lst)) + +ULP_PREPROCESSOR_ARGS := \ + $(addprefix -I ,$(COMPONENT_INCLUDES)) \ + $(addprefix -I ,$(COMPONENT_EXTRA_INCLUDES)) \ + -I$(COMPONENT_PATH) -D__ASSEMBLER__ + +-include $(ULP_DEP) + +# Preprocess LD script used to link ULP program +$(ULP_LD_SCRIPT): $(ULP_LD_TEMPLATE) + $(summary) CPP $(notdir $@) + $(CC) $(CPPFLAGS) -MT $(ULP_LD_SCRIPT) -E -P -xc -o $@ $(ULP_PREPROCESSOR_ARGS) $< + +# Generate preprocessed assembly files. +# To inspect these preprocessed files, add a ".PRECIOUS: %.ulp.pS" rule. +%.ulp.pS: $(COMPONENT_PATH)/ulp/%.S + $(summary) CPP $(notdir $<) + $(CC) $(CPPFLAGS) -MT $(patsubst %.ulp.pS,%.ulp.o,$@) -E -P -xc -o $@ $(ULP_PREPROCESSOR_ARGS) $< + +# Compiled preprocessed files into object files. +%.ulp.o: %.ulp.pS + $(summary) ULP_AS $(notdir $@) + $(ULP_AS) -al=$(patsubst %.ulp.o,%.ulp.lst,$@) -o $@ $< + +# Link object files and generate map file +$(ULP_ELF): $(ULP_OBJECTS) $(ULP_LD_SCRIPT) + $(summary) ULP_LD $(notdir $@) + $(ULP_LD) -o $@ -A elf32-esp32ulp -Map=$(ULP_MAP) -T $(ULP_LD_SCRIPT) $< + +# Dump the list of global symbols in a convenient format. +$(ULP_SYM): $(ULP_ELF) + $(ULP_NM) -g -f posix $< > $@ + +# Dump the binary for inclusion into the project +$(COMPONENT_BUILD_DIR)/$(ULP_BIN): $(ULP_ELF) + $(summary) ULP_BIN $(notdir $@) + $(ULP_OBJCOPY) -O binary $< $@ + +# Left and right side of the rule are the same, but the right side +# is given as an absolute path. +# (Make can not resolve such things automatically) +$(ULP_EXPORTS_HEADER): $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER) + +# Artificial intermediate target to trigger generation of .h and .ld files. +.INTERMEDIATE: $(COMPONENT_NAME)_ulp_mapgen_intermediate + +$(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER)\ +$(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD): $(COMPONENT_NAME)_ulp_mapgen_intermediate + +# Convert the symbols list into a header file and linker export script. +$(COMPONENT_NAME)_ulp_mapgen_intermediate: $(ULP_SYM) + $(summary) ULP_MAPGEN $(notdir $<) + $(ULP_MAP_GEN) -s $(ULP_SYM) -o $(ULP_EXPORTS_LD:.ld=) + +# Building the component separately from the project should result in +# ULP files being built. +build: $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_HEADER) \ + $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD) \ + $(COMPONENT_BUILD_DIR)/$(ULP_BIN) + +# Objects listed as being dependent on $(ULP_EXPORTS_HEADER) must also +# depend on $(ULP_SYM), to order build steps correctly. +$(ULP_EXP_DEP_OBJECTS) : $(ULP_EXPORTS_HEADER) $(ULP_SYM) + +# Finally, set all the variables processed by the build system. +COMPONENT_EXTRA_CLEAN := $(ULP_OBJECTS) \ + $(ULP_LD_SCRIPT) \ + $(ULP_PREPROCESSED) \ + $(ULP_ELF) $(ULP_BIN) \ + $(ULP_MAP) $(ULP_SYM) \ + $(ULP_EXPORTS_LD) \ + $(ULP_EXPORTS_HEADER) \ + $(ULP_DEP) \ + $(ULP_LISTINGS) + +COMPONENT_EMBED_FILES := $(COMPONENT_BUILD_DIR)/$(ULP_BIN) +COMPONENT_ADD_LDFLAGS := -l$(COMPONENT_NAME) -T $(COMPONENT_BUILD_DIR)/$(ULP_EXPORTS_LD) +COMPONENT_EXTRA_INCLUDES := $(COMPONENT_BUILD_DIR) diff --git a/components/ulp/esp32ulp_mapgen.py b/components/ulp/esp32ulp_mapgen.py new file mode 100755 index 000000000..12777afb1 --- /dev/null +++ b/components/ulp/esp32ulp_mapgen.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# esp32ulp_mapgen utility converts a symbol list provided by nm into an export script +# for the linker and a header file. +# +# Copyright (c) 2016-2017 Espressif Systems (Shanghai) PTE LTD. +# Distributed under the terms of Apache License v2.0 found in the top-level LICENSE file. + +from optparse import OptionParser + +BASE_ADDR = 0x50000000; + +def gen_ld_h_from_sym(f_sym, f_ld, f_h): + f_ld.write("/* Variable definitions for ESP32ULP linker\n"); + f_ld.write(" * This file is generated automatically by esp32ulp_mapgen.py utility.\n"); + f_ld.write(" */\n\n"); + f_h.write("// Variable definitions for ESP32ULP\n"); + f_h.write("// This file is generated automatically by esp32ulp_mapgen.py utility\n\n"); + f_h.write("#pragma once\n\n"); + + for line in f_sym: + name, _, addr_str = line.split() + addr = int(addr_str, 16) + BASE_ADDR; + f_h.write("extern uint32_t ulp_{0};\n".format(name)); + f_ld.write("PROVIDE ( ulp_{0} = 0x{1:08x} );\n".format(name, addr)) + + +def main(): + description = ( "This application generates .h and .ld files for symbols defined in input file. " + "The input symbols file can be generated using nm utility like this: " + "esp32-ulp-nm -g -f posix > " ); + + parser = OptionParser(description=description) + parser.add_option("-s", "--symfile", dest="symfile", + help="symbols file name", metavar="SYMFILE") + parser.add_option("-o", "--outputfile", dest="outputfile", + help="destination .h and .ld files name prefix", metavar="OUTFILE") + + (options, args) = parser.parse_args() + if options.symfile is None: + parser.print_help() + return 1 + + if options.outputfile is None: + parser.print_help() + return 1 + + with open(options.outputfile + ".h", 'w') as f_h, \ + open(options.outputfile + ".ld", 'w') as f_ld, \ + open(options.symfile) as f_sym: \ + gen_ld_h_from_sym(f_sym, f_ld, f_h) + return 0 + +if __name__ == "__main__": + exit(main()); diff --git a/components/ulp/include/esp32/ulp.h b/components/ulp/include/esp32/ulp.h index 7b434a06a..818a79628 100644 --- a/components/ulp/include/esp32/ulp.h +++ b/components/ulp/include/esp32/ulp.h @@ -847,6 +847,34 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) { */ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* program, size_t* psize); +/** + * @brief Load ULP program binary into RTC memory + * + * ULP program binary should have the following format (all values little-endian): + * + * 1. MAGIC, (value 0x00706c75, 4 bytes) + * 2. TEXT_OFFSET, offset of .text section from binary start (2 bytes) + * 3. TEXT_SIZE, size of .text section (2 bytes) + * 4. DATA_SIZE, size of .data section (2 bytes) + * 5. BSS_SIZE, size of .bss section (2 bytes) + * 6. (TEXT_OFFSET - 16) bytes of arbitrary data (will not be loaded into RTC memory) + * 7. .text section + * 8. .data section + * + * Linker script in components/ulp/ld/esp32.ulp.ld produces ELF files which + * correspond to this format. This linker script produces binaries with load_addr == 0. + * + * @param load_addr address where the program should be loaded, expressed in 32-bit words + * @param program_binary pointer to program binary + * @param program_size size of the program binary + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if load_addr is out of range + * - ESP_ERR_INVALID_SIZE if program_size doesn't match (TEXT_OFFSET + TEXT_SIZE + DATA_SIZE) + * - ESP_ERR_NOT_SUPPORTED if the magic number is incorrect + */ +esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t* program_binary, size_t program_size); + /** * @brief Run the program loaded into RTC memory * @param entry_point entry point, expressed in 32-bit words diff --git a/components/ulp/ld/esp32.ulp.ld b/components/ulp/ld/esp32.ulp.ld new file mode 100644 index 000000000..4c29ea59c --- /dev/null +++ b/components/ulp/ld/esp32.ulp.ld @@ -0,0 +1,35 @@ +#include "sdkconfig.h" + +#define ULP_BIN_MAGIC 0x00706c75 +#define HEADER_SIZE 12 +MEMORY +{ + ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM +} + +SECTIONS +{ + .text : AT(HEADER_SIZE) + { + *(.text) + } >ram + .data : + { + . = ALIGN(4); + *(.data) + } >ram + .bss : + { + . = ALIGN(4); + *(.bss) + } >ram + + .header : AT(0) + { + LONG(ULP_BIN_MAGIC) + SHORT(LOADADDR(.text)) + SHORT(SIZEOF(.text)) + SHORT(SIZEOF(.data)) + SHORT(SIZEOF(.bss)) + } +} diff --git a/components/ulp/ulp.c b/components/ulp/ulp.c index a6e462d1b..4cf9b7a4d 100644 --- a/components/ulp/ulp.c +++ b/components/ulp/ulp.c @@ -27,239 +27,17 @@ #include "sdkconfig.h" -static const char* TAG = "ulp"; - typedef struct { - uint32_t label : 16; - uint32_t addr : 11; - uint32_t unused : 1; - uint32_t type : 4; -} reloc_info_t; + uint32_t magic; + uint16_t text_offset; + uint16_t text_size; + uint16_t data_size; + uint16_t bss_size; +} ulp_binary_header_t; -#define RELOC_TYPE_LABEL 0 -#define RELOC_TYPE_BRANCH 1 +#define ULP_BINARY_MAGIC_ESP32 (0x00706c75) -/* This record means: there is a label at address - * insn_addr, with number label_num. - */ -#define RELOC_INFO_LABEL(label_num, insn_addr) (reloc_info_t) { \ - .label = label_num, \ - .addr = insn_addr, \ - .unused = 0, \ - .type = RELOC_TYPE_LABEL } - -/* This record means: there is a branch instruction at - * insn_addr, it needs to be changed to point to address - * of label label_num. - */ -#define RELOC_INFO_BRANCH(label_num, insn_addr) (reloc_info_t) { \ - .label = label_num, \ - .addr = insn_addr, \ - .unused = 0, \ - .type = RELOC_TYPE_BRANCH } - - -/* Processing branch and label macros involves four steps: - * - * 1. Iterate over program and count all instructions - * with "macro" opcode. Allocate relocations array - * with number of entries equal to number of macro - * instructions. - * - * 2. Remove all fake instructions with "macro" opcode - * and record their locations into relocations array. - * Removal is done using two pointers. Instructions - * are read from read_ptr, and written to write_ptr. - * When a macro instruction is encountered, - * its contents are recorded into the appropriate - * table, and then read_ptr is advanced again. - * When a real instruction is encountered, it is - * read via read_ptr and written to write_ptr. - * In the end, all macro instructions are removed, - * size of the program (expressed in words) is - * reduced by the total number of macro instructions - * which were present. - * - * 3. Sort relocations array by label number, and then - * by type ("label" or "branch") if label numbers - * match. This is done to simplify lookup on the next - * step. - * - * 4. Iterate over entries of relocations table. - * For each label number, label entry comes first - * because the array was sorted at the previous step. - * Label address is recorded, and all subsequent - * "branch" entries which point to the same label number - * are processed. For each branch entry, correct offset - * or absolute address is calculated, depending on branch - * type, and written into the appropriate field of - * the instruction. - * - */ - -static esp_err_t do_single_reloc(ulp_insn_t* program, uint32_t load_addr, - reloc_info_t label_info, reloc_info_t branch_info) -{ - size_t insn_offset = branch_info.addr - load_addr; - ulp_insn_t* insn = &program[insn_offset]; - // B and BX have the same layout of opcode/sub_opcode fields, - // and share the same opcode - assert(insn->b.opcode == OPCODE_BRANCH - && "branch macro was applied to a non-branch instruction"); - switch (insn->b.sub_opcode) { - case SUB_OPCODE_B: { - int32_t offset = ((int32_t) label_info.addr) - ((int32_t) branch_info.addr); - uint32_t abs_offset = abs(offset); - uint32_t sign = (offset >= 0) ? 0 : 1; - if (abs_offset > 127) { - ESP_LOGW(TAG, "target out of range: branch from %x to %x", - branch_info.addr, label_info.addr); - return ESP_ERR_ULP_BRANCH_OUT_OF_RANGE; - } - insn->b.offset = abs_offset; - insn->b.sign = sign; - break; - } - case SUB_OPCODE_BX: { - assert(insn->bx.reg == 0 && - "relocation applied to a jump with offset in register"); - insn->bx.addr = label_info.addr; - break; - } - default: - assert(false && "unexpected sub-opcode"); - } - return ESP_OK; -} - -esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* program, size_t* psize) -{ - const ulp_insn_t* read_ptr = program; - const ulp_insn_t* end = program + *psize; - size_t macro_count = 0; - // step 1: calculate number of macros - while (read_ptr < end) { - ulp_insn_t r_insn = *read_ptr; - if (r_insn.macro.opcode == OPCODE_MACRO) { - ++macro_count; - } - ++read_ptr; - } - size_t real_program_size = *psize - macro_count; - const size_t ulp_mem_end = CONFIG_ULP_COPROC_RESERVE_MEM / sizeof(ulp_insn_t); - if (load_addr > ulp_mem_end) { - ESP_LOGW(TAG, "invalid load address %x, max is %x", - load_addr, ulp_mem_end); - return ESP_ERR_ULP_INVALID_LOAD_ADDR; - } - if (real_program_size + load_addr > ulp_mem_end) { - ESP_LOGE(TAG, "program too big: %d words, max is %d words", - real_program_size, ulp_mem_end); - return ESP_ERR_ULP_SIZE_TOO_BIG; - } - // If no macros found, copy the program and return. - if (macro_count == 0) { - memcpy(((ulp_insn_t*) RTC_SLOW_MEM) + load_addr, program, *psize * sizeof(ulp_insn_t)); - return ESP_OK; - } - reloc_info_t* reloc_info = - (reloc_info_t*) malloc(sizeof(reloc_info_t) * macro_count); - if (reloc_info == NULL) { - return ESP_ERR_NO_MEM; - } - - // step 2: record macros into reloc_info array - // and remove them from then program - read_ptr = program; - ulp_insn_t* output_program = ((ulp_insn_t*) RTC_SLOW_MEM) + load_addr; - ulp_insn_t* write_ptr = output_program; - uint32_t cur_insn_addr = load_addr; - reloc_info_t* cur_reloc = reloc_info; - while (read_ptr < end) { - ulp_insn_t r_insn = *read_ptr; - if (r_insn.macro.opcode == OPCODE_MACRO) { - switch(r_insn.macro.sub_opcode) { - case SUB_OPCODE_MACRO_LABEL: - *cur_reloc = RELOC_INFO_LABEL(r_insn.macro.label, - cur_insn_addr); - break; - case SUB_OPCODE_MACRO_BRANCH: - *cur_reloc = RELOC_INFO_BRANCH(r_insn.macro.label, - cur_insn_addr); - break; - default: - assert(0 && "invalid sub_opcode for macro insn"); - } - ++read_ptr; - assert(read_ptr != end && "program can not end with macro insn"); - ++cur_reloc; - } else { - // normal instruction (not a macro) - *write_ptr = *read_ptr; - ++read_ptr; - ++write_ptr; - ++cur_insn_addr; - } - } - - // step 3: sort relocations array - int reloc_sort_func(const void* p_lhs, const void* p_rhs) { - const reloc_info_t lhs = *(const reloc_info_t*) p_lhs; - const reloc_info_t rhs = *(const reloc_info_t*) p_rhs; - if (lhs.label < rhs.label) { - return -1; - } else if (lhs.label > rhs.label) { - return 1; - } - // label numbers are equal - if (lhs.type < rhs.type) { - return -1; - } else if (lhs.type > rhs.type) { - return 1; - } - - // both label number and type are equal - return 0; - } - qsort(reloc_info, macro_count, sizeof(reloc_info_t), - reloc_sort_func); - - // step 4: walk relocations array and fix instructions - reloc_info_t* reloc_end = reloc_info + macro_count; - cur_reloc = reloc_info; - while(cur_reloc < reloc_end) { - reloc_info_t label_info = *cur_reloc; - assert(label_info.type == RELOC_TYPE_LABEL); - ++cur_reloc; - while (cur_reloc < reloc_end) { - if (cur_reloc->type == RELOC_TYPE_LABEL) { - if(cur_reloc->label == label_info.label) { - ESP_LOGE(TAG, "duplicate label definition: %d", - label_info.label); - free(reloc_info); - return ESP_ERR_ULP_DUPLICATE_LABEL; - } - break; - } - if (cur_reloc->label != label_info.label) { - ESP_LOGE(TAG, "branch to an inexistent label: %d", - cur_reloc->label); - free(reloc_info); - return ESP_ERR_ULP_UNDEFINED_LABEL; - } - esp_err_t rc = do_single_reloc(output_program, load_addr, - label_info, *cur_reloc); - if (rc != ESP_OK) { - free(reloc_info); - return rc; - } - ++cur_reloc; - } - } - free(reloc_info); - *psize = real_program_size; - return ESP_OK; -} +static const char* TAG = "ulp"; esp_err_t ulp_run(uint32_t entry_point) { @@ -279,3 +57,46 @@ esp_err_t ulp_run(uint32_t entry_point) SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); return ESP_OK; } + +esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t* program_binary, size_t program_size) +{ + size_t program_size_bytes = program_size * sizeof(uint32_t); + size_t load_addr_bytes = load_addr * sizeof(uint32_t); + + if (program_size_bytes < sizeof(ulp_binary_header_t)) { + return ESP_ERR_INVALID_SIZE; + } + if (load_addr_bytes > CONFIG_ULP_COPROC_RESERVE_MEM) { + return ESP_ERR_INVALID_ARG; + } + if (load_addr_bytes + program_size_bytes > CONFIG_ULP_COPROC_RESERVE_MEM) { + return ESP_ERR_INVALID_SIZE; + } + + // Make a copy of a header in case program_binary isn't aligned + ulp_binary_header_t header; + memcpy(&header, program_binary, sizeof(header)); + + if (header.magic != ULP_BINARY_MAGIC_ESP32) { + return ESP_ERR_NOT_SUPPORTED; + } + + size_t total_size = (size_t) header.text_offset + (size_t) header.text_size + + (size_t) header.data_size; + + ESP_LOGD(TAG, "program_size_bytes: %d total_size: %d offset: %d .text: %d, .data: %d, .bss: %d", + program_size_bytes, total_size, header.text_offset, + header.text_size, header.data_size, header.bss_size); + + if (total_size != program_size_bytes) { + return ESP_ERR_INVALID_SIZE; + } + + size_t text_data_size = header.text_size + header.data_size; + uint8_t* base = (uint8_t*) RTC_SLOW_MEM; + + memcpy(base + load_addr_bytes, program_binary + header.text_offset, text_data_size); + memset(base + load_addr_bytes + text_data_size, 0, header.bss_size); + + return ESP_OK; +} diff --git a/components/ulp/ulp_macro.c b/components/ulp/ulp_macro.c new file mode 100644 index 000000000..eae72ffe0 --- /dev/null +++ b/components/ulp/ulp_macro.c @@ -0,0 +1,262 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "esp_attr.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp32/ulp.h" + +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" + +#include "sdkconfig.h" + +static const char* TAG = "ulp"; + +typedef struct { + uint32_t label : 16; + uint32_t addr : 11; + uint32_t unused : 1; + uint32_t type : 4; +} reloc_info_t; + +#define RELOC_TYPE_LABEL 0 +#define RELOC_TYPE_BRANCH 1 + +/* This record means: there is a label at address + * insn_addr, with number label_num. + */ +#define RELOC_INFO_LABEL(label_num, insn_addr) (reloc_info_t) { \ + .label = label_num, \ + .addr = insn_addr, \ + .unused = 0, \ + .type = RELOC_TYPE_LABEL } + +/* This record means: there is a branch instruction at + * insn_addr, it needs to be changed to point to address + * of label label_num. + */ +#define RELOC_INFO_BRANCH(label_num, insn_addr) (reloc_info_t) { \ + .label = label_num, \ + .addr = insn_addr, \ + .unused = 0, \ + .type = RELOC_TYPE_BRANCH } + + +/* Processing branch and label macros involves four steps: + * + * 1. Iterate over program and count all instructions + * with "macro" opcode. Allocate relocations array + * with number of entries equal to number of macro + * instructions. + * + * 2. Remove all fake instructions with "macro" opcode + * and record their locations into relocations array. + * Removal is done using two pointers. Instructions + * are read from read_ptr, and written to write_ptr. + * When a macro instruction is encountered, + * its contents are recorded into the appropriate + * table, and then read_ptr is advanced again. + * When a real instruction is encountered, it is + * read via read_ptr and written to write_ptr. + * In the end, all macro instructions are removed, + * size of the program (expressed in words) is + * reduced by the total number of macro instructions + * which were present. + * + * 3. Sort relocations array by label number, and then + * by type ("label" or "branch") if label numbers + * match. This is done to simplify lookup on the next + * step. + * + * 4. Iterate over entries of relocations table. + * For each label number, label entry comes first + * because the array was sorted at the previous step. + * Label address is recorded, and all subsequent + * "branch" entries which point to the same label number + * are processed. For each branch entry, correct offset + * or absolute address is calculated, depending on branch + * type, and written into the appropriate field of + * the instruction. + * + */ + +static esp_err_t do_single_reloc(ulp_insn_t* program, uint32_t load_addr, + reloc_info_t label_info, reloc_info_t branch_info) +{ + size_t insn_offset = branch_info.addr - load_addr; + ulp_insn_t* insn = &program[insn_offset]; + // B and BX have the same layout of opcode/sub_opcode fields, + // and share the same opcode + assert(insn->b.opcode == OPCODE_BRANCH + && "branch macro was applied to a non-branch instruction"); + switch (insn->b.sub_opcode) { + case SUB_OPCODE_B: { + int32_t offset = ((int32_t) label_info.addr) - ((int32_t) branch_info.addr); + uint32_t abs_offset = abs(offset); + uint32_t sign = (offset >= 0) ? 0 : 1; + if (abs_offset > 127) { + ESP_LOGW(TAG, "target out of range: branch from %x to %x", + branch_info.addr, label_info.addr); + return ESP_ERR_ULP_BRANCH_OUT_OF_RANGE; + } + insn->b.offset = abs_offset; + insn->b.sign = sign; + break; + } + case SUB_OPCODE_BX: { + assert(insn->bx.reg == 0 && + "relocation applied to a jump with offset in register"); + insn->bx.addr = label_info.addr; + break; + } + default: + assert(false && "unexpected sub-opcode"); + } + return ESP_OK; +} + +esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* program, size_t* psize) +{ + const ulp_insn_t* read_ptr = program; + const ulp_insn_t* end = program + *psize; + size_t macro_count = 0; + // step 1: calculate number of macros + while (read_ptr < end) { + ulp_insn_t r_insn = *read_ptr; + if (r_insn.macro.opcode == OPCODE_MACRO) { + ++macro_count; + } + ++read_ptr; + } + size_t real_program_size = *psize - macro_count; + const size_t ulp_mem_end = CONFIG_ULP_COPROC_RESERVE_MEM / sizeof(ulp_insn_t); + if (load_addr > ulp_mem_end) { + ESP_LOGW(TAG, "invalid load address %x, max is %x", + load_addr, ulp_mem_end); + return ESP_ERR_ULP_INVALID_LOAD_ADDR; + } + if (real_program_size + load_addr > ulp_mem_end) { + ESP_LOGE(TAG, "program too big: %d words, max is %d words", + real_program_size, ulp_mem_end); + return ESP_ERR_ULP_SIZE_TOO_BIG; + } + // If no macros found, copy the program and return. + if (macro_count == 0) { + memcpy(((ulp_insn_t*) RTC_SLOW_MEM) + load_addr, program, *psize * sizeof(ulp_insn_t)); + return ESP_OK; + } + reloc_info_t* reloc_info = + (reloc_info_t*) malloc(sizeof(reloc_info_t) * macro_count); + if (reloc_info == NULL) { + return ESP_ERR_NO_MEM; + } + + // step 2: record macros into reloc_info array + // and remove them from then program + read_ptr = program; + ulp_insn_t* output_program = ((ulp_insn_t*) RTC_SLOW_MEM) + load_addr; + ulp_insn_t* write_ptr = output_program; + uint32_t cur_insn_addr = load_addr; + reloc_info_t* cur_reloc = reloc_info; + while (read_ptr < end) { + ulp_insn_t r_insn = *read_ptr; + if (r_insn.macro.opcode == OPCODE_MACRO) { + switch(r_insn.macro.sub_opcode) { + case SUB_OPCODE_MACRO_LABEL: + *cur_reloc = RELOC_INFO_LABEL(r_insn.macro.label, + cur_insn_addr); + break; + case SUB_OPCODE_MACRO_BRANCH: + *cur_reloc = RELOC_INFO_BRANCH(r_insn.macro.label, + cur_insn_addr); + break; + default: + assert(0 && "invalid sub_opcode for macro insn"); + } + ++read_ptr; + assert(read_ptr != end && "program can not end with macro insn"); + ++cur_reloc; + } else { + // normal instruction (not a macro) + *write_ptr = *read_ptr; + ++read_ptr; + ++write_ptr; + ++cur_insn_addr; + } + } + + // step 3: sort relocations array + int reloc_sort_func(const void* p_lhs, const void* p_rhs) { + const reloc_info_t lhs = *(const reloc_info_t*) p_lhs; + const reloc_info_t rhs = *(const reloc_info_t*) p_rhs; + if (lhs.label < rhs.label) { + return -1; + } else if (lhs.label > rhs.label) { + return 1; + } + // label numbers are equal + if (lhs.type < rhs.type) { + return -1; + } else if (lhs.type > rhs.type) { + return 1; + } + + // both label number and type are equal + return 0; + } + qsort(reloc_info, macro_count, sizeof(reloc_info_t), + reloc_sort_func); + + // step 4: walk relocations array and fix instructions + reloc_info_t* reloc_end = reloc_info + macro_count; + cur_reloc = reloc_info; + while(cur_reloc < reloc_end) { + reloc_info_t label_info = *cur_reloc; + assert(label_info.type == RELOC_TYPE_LABEL); + ++cur_reloc; + while (cur_reloc < reloc_end) { + if (cur_reloc->type == RELOC_TYPE_LABEL) { + if(cur_reloc->label == label_info.label) { + ESP_LOGE(TAG, "duplicate label definition: %d", + label_info.label); + free(reloc_info); + return ESP_ERR_ULP_DUPLICATE_LABEL; + } + break; + } + if (cur_reloc->label != label_info.label) { + ESP_LOGE(TAG, "branch to an inexistent label: %d", + cur_reloc->label); + free(reloc_info); + return ESP_ERR_ULP_UNDEFINED_LABEL; + } + esp_err_t rc = do_single_reloc(output_program, load_addr, + label_info, *cur_reloc); + if (rc != ESP_OK) { + free(reloc_info); + return rc; + } + ++cur_reloc; + } + } + free(reloc_info); + *psize = real_program_size; + return ESP_OK; +} diff --git a/docs/ulp.rst b/docs/ulp.rst index 4ee6ed7a2..5d12e7c34 100644 --- a/docs/ulp.rst +++ b/docs/ulp.rst @@ -1 +1,161 @@ -.. include:: ../components/ulp/README.rst +ULP coprocessor programming +=========================== + +.. toctree:: + :maxdepth: 1 + + Instruction set reference + Programming using macros (legacy) + + +ULP (Ultra Low Power) coprocessor is a simple FSM which is designed to perform measurements using ADC, temperature sensor, and external I2C sensors, while main processors are in deep sleep mode. ULP coprocessor can access RTC_SLOW_MEM memory region, and registers in RTC_CNTL, RTC_IO, and SARADC peripherals. ULP coprocessor uses fixed-width 32-bit instructions, 32-bit memory addressing, and has 4 general purpose 16-bit registers. + +Installing the toolchain +------------------------ + +ULP coprocessor code is written in assembly and compiled using the `binutils-esp32ulp toolchain`_. + +1. Download the toolchain using the links listed on this page: +https://github.com/espressif/binutils-esp32ulp/wiki#downloads + +2. Extract the toolchain into a directory, and add the path to the ``bin/`` directory of the toolchain to the ``PATH`` environment variable. + +Compiling ULP code +------------------ + +To compile ULP code as part of a component, the following steps must be taken: + +1. ULP code, written in assembly, must be added to one or more files with `.S` extension. These files must be placed into a separate directory inside component directory, for instance `ulp/`. + +.. note: This directory should not be added to the ``COMPONENT_SRCDIRS`` environment variable. The logic behind this is that the ESP-IDF build system will compile files found in ``COMPONENT_SRCDIRS`` based on their extensions. For ``.S`` files, ``xtensa-esp32-elf-as`` assembler is used. This is not desirable for ULP assembly files, so the easiest way to achieve the distinction is by placing ULP assembly files into a separate directory. + +2. Modify the component makefile, adding the following:: + + ULP_APP_NAME ?= ulp_$(COMPONENT_NAME) + ULP_S_SOURCES = $(COMPONENT_PATH)/ulp/ulp_source_file.S + ULP_EXP_DEP_OBJECTS := main.o + include $(IDF_PATH)/components/ulp/component_ulp_common.mk + + Here is each line explained: + + ULP_APP_NAME + Name of the generated ULP application, without an extension. This name is used for build products of the ULP application: ELF file, map file, binary file, generated header file, and generated linker export file. + + ULP_S_SOURCES + List of assembly files to be passed to the ULP assembler. These must be absolute paths, i.e. start with ``$(COMPONENT_PATH)``. Consider using ``$(addprefix)`` function if more than one file needs to be listed. Paths are relative to component build directory, so prefixing them is not necessary. + + ULP_EXP_DEP_OBJECTS + List of object files names within the component which include the generated header file. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See section below explaining the concept of generated header files for ULP applications. + + include $(IDF_PATH)/components/ulp/component_ulp_common.mk + Includes common definitions of ULP build steps. Defines build targets for ULP object files, ELF file, binary file, etc. + +3. Build the application as usual (e.g. `make app`) + + Inside, the build system will take the following steps to build ULP program: + + 1. **Run each assembly file (foo.S) through C preprocessor.** This step generates the preprocessed assembly files (foo.ulp.pS) in the component build directory. This step also generates dependency files (foo.ulp.d). + + 2. **Run preprocessed assembly sources through assembler.** This produces objects (foo.ulp.o) and listing (foo.ulp.lst) files. Listing files are generated for debugging purposes and are not used at later stages of build process. + + 3. **Run linker script template through C preprocessor.** The template is located in components/ulp/ld directory. + + 4. **Link object files into an output ELF file** (ulp_app_name.elf). Map file (ulp_app_name.map) generated at this stage may be useful for debugging purposes. + + 5. **Dump contents of the ELF file into binary** (ulp_app_name.bin) for embedding into the application. + + 6. **Generate list of global symbols** (ulp_app_name.sym) in the ELF file using esp32ulp-elf-nm. + + 7. **Create LD export script and header file** (ulp_app_name.ld and ulp_app_name.h) containing the symbols from ulp_app_name.sym. This is done using esp32ulp_mapgen.py utility. + + 8. **Add the generated binary to the list of binary files** to be emedded into the application. + +Accessing ULP program variables +------------------------------- + +Global symbols defined in the ULP program may be used inside the main program. + +For example, ULP program may define a variable ``measurement_count`` which will define the number of ADC measurements the program needs to make before waking up the chip from deep sleep:: + + .global measurement_count + measurement_count: .long 0 + + /* later, use measurement_count */ + move r3, measurement_count + ld r3, r3, 0 + +Main program needs to initialize this variable before ULP program is started. Build system makes this possible by generating a ``$(ULP_APP_NAME).h`` and ``$(ULP_APP_NAME).ld`` files which define global symbols present in the ULP program. This files include each global symbol defined in the ULP program, prefixed with ``ulp_``. + +The header file contains declaration of the symbol:: + + extern uint32_t ulp_measurement_count; + +Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take address of the symbol and cast to the appropriate type. + +The generated linker script file defines locations of symbols in RTC_SLOW_MEM:: + + PROVIDE ( ulp_measurement_count = 0x50000060 ); + +To access ULP program variables from the main program, include the generated header file and use variables as one normally would:: + + #include "ulp_app_name.h" + + // later + void init_ulp_vars() { + ulp_measurement_count = 64; + } + +Note that ULP program can only use lower 16 bits of each 32-bit word in RTC memory, because the registers are 16-bit, and there is no instruction to load from high part of the word. + +Likewise, ULP store instruction writes register value into the lower 16 bit part of the 32-bit word. Upper 16 bits are written with a value which depends on the address of the store instruction, so when reading variables written by the ULP, main application needs to mask upper 16 bits, e.g.:: + + printf("Last measurement value: %d\n", ulp_last_measurement & UINT16_MAX); + +Starting the ULP program +------------------------ + +To run a ULP program, main application needs to load the ULP program into RTC memory using ``ulp_load_binary`` function, and then start it using ``ulp_run`` function. + +Note that "Enable Ultra Low Power (ULP) Coprocessor" option must be enabled in menuconfig in order to reserve memory for the ULP. "RTC slow memory reserved for coprocessor" option must be set to a value sufficient to store ULP code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one. + +Each ULP program is embedded into the ESP-IDF application as a binary blob. Application can reference this blob and load it in the following way (suppose ULP_APP_NAME was defined to ``ulp_app_name``:: + + extern const uint8_t bin_start[] asm("_binary_ulp_app_name_bin_start"); + extern const uint8_t bin_end[] asm("_binary_ulp_app_name_bin_end"); + + void start_ulp_program() { + ESP_ERROR_CHECK( ulp_load_binary( + 0 /* load address, set to 0 when using default linker scripts */, + bin_start, + (bin_end - bin_start) / sizeof(uint32_t)) ); + } + +.. doxygenfunction:: ulp_load_binary + +Once the program is loaded into RTC memory, application can start it, passing the address of the entry point to ``ulp_run`` function:: + + ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)) ); + +.. doxygenfunction:: ulp_run + +Declaration of the entry point symbol comes from the above mentioned generated header file, ``$(ULP_APP_NAME).h``. In assembly source of the ULP application, this symbol must be marked as ``.global``:: + + + .global entry + entry: + /* code starts here */ + + +ULP program flow +---------------- + +ULP coprocessor is started by a timer. The timer is started once ``ulp_run`` is called. The timer counts a number of RTC_SLOW_CLK ticks (by default, produced by an internal 150kHz RC oscillator). The number of ticks is set using ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers (x = 0..4). When starting the ULP for the first time, ``SENS_ULP_CP_SLEEP_CYC0_REG`` will be used to obtain the number of timer ticks. Later the ULP program can select another ``SENS_ULP_CP_SLEEP_CYCx_REG`` register using ``sleep`` instruction. + +Once the timer counts the number of ticks set by the selected ``SENS_ULP_CP_SLEEP_CYCx_REG`` register, ULP coprocessor powers up and starts running the program from the entry point set in the call to ``ulp_run``. + +The program runs until it encounters a ``halt`` instruction or an illegal instruction. Once the program halts, ULP coprocessor powers down, and the timer is started again. + +To disable the timer (effectively preventing the ULP program from running again), clear the ``RTC_CNTL_ULP_CP_SLP_TIMER_EN`` bit in the ``RTC_CNTL_STATE0_REG`` register. This can be done both from ULP code and from the main program. + + +.. _binutils-esp32ulp toolchain: https://github.com/espressif/binutils-esp32ulp diff --git a/docs/ulp_instruction_set.rst b/docs/ulp_instruction_set.rst new file mode 100755 index 000000000..5a104a7e9 --- /dev/null +++ b/docs/ulp_instruction_set.rst @@ -0,0 +1,768 @@ +ULP coprocessor instruction set ++++++++++++++++++++++++++++++++ + +This document provides details about the instructions used by ESP32 ULP coprocessor assembler. + +ULP coprocessor has 4 16-bit general purpose registers, labeled R0, R1, R2, R3. It also has an 8-bit counter register (stage_cnt) which can be used to implement loops. Stage count regiter is accessed using special instructions. + +ULP coprocessor can access 8k bytes of RTC_SLOW_MEM memory region. Memory is addressed in 32-bit word units. It can also access peripheral registers in RTC_CNTL, RTC_IO, and SENS peripherals. + +All instructions are 32-bit. Jump instructions, ALU instructions, peripheral register and memory access instructions are executed in 1 cycle. Instructions which work with peripherals (TSENS, ADC, I2C) take variable number of cycles, depending on peripheral operation. + +The instruction syntax is case insensitive. Upper and lower case letters can be used and intermixed arbitrarily. This is true both for register names and instruction names. + +Note about addressing +--------------------- +ESP32 ULP coprocessor's JUMP, ST, LD instructions which take register as an argument (jump address, store/load base address) expect the argument to be expressed in 32-bit words. + +Consider the following example program:: + + entry: + NOP + NOP + NOP + NOP + loop: + MOVE R1, loop + JUMP R1 + +When this program is assembled and linked, address of label ``loop`` will be equal to 16 (expressed in bytes). However `JUMP` instruction expects the address stored in register to be expressed in 32-bit words. To account for this common use case, assembler will convert the address of label `loop` from bytes to words, when generating ``MOVE`` instruction, so the code generated code will be equivalent to:: + + 0000 NOP + 0004 NOP + 0008 NOP + 000c NOP + 0010 MOVE R1, 4 + 0014 JUMP R1 + +The other case is when the argument of ``MOVE`` instruction is not a label but a constant. In this case assembler will use the value as is, without any conversion:: + + .set val, 0x10 + MOVE R1, val + +In this case, value loaded into R1 will be ``0x10``. + +Similar considerations apply to ``LD`` and ``ST`` instructions. Consider the following code:: + + .global array + array: .long 0 + .long 0 + .long 0 + .long 0 + + MOVE R1, array + MOVE R2, 0x1234 + ST R2, R1, 0 // write value of R2 into the first array element, + // i.e. array[0] + + ST R2, R1, 4 // write value of R2 into the second array element + // (4 byte offset), i.e. array[1] + + ADD R1, R1, 2 // this increments address by 2 words (8 bytes) + ST R2, R1, 0 // write value of R2 into the third array element, + // i.e. array[2] + +**NOP** - no operation +---------------------- + +**Syntax:** + **NOP** +**Operands:** + None +**Description:** + No operation is performed. Only the PC is incremented. + +**Example**:: + + 1: NOP + + +**ADD** - Add to register +------------------------- + +**Syntax:** + **ADD** *Rdst, Rsrc1, Rsrc2* + + **ADD** *Rdst, Rsrc1, imm* + + +**Operands:** + - *Rdst* - Register R[0..3] + - *Rsrc1* - Register R[0..3] + - *Rsrc2* - Register R[0..3] + - *Imm* - 16-bit signed value + + +**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**:: + + 1: ADD R1, R2, R3 //R1 = R2 + R3 + + 2: Add R1, R2, 0x1234 //R1 = R2 + 0x1234 + + 3: .set value1, 0x03 //constant value1=0x03 + Add R1, R2, value1 //R1 = R2 + value1 + + + 4: .global label //declaration of variable label + Add R1, R2, label //R1 = R2 + label + ... + label: nop //definition of variable label + + +**SUB** - Subtract from register +-------------------------------- + +**Syntax:** + **SUB** *Rdst, Rsrc1, Rsrc2* + + **SUB** *Rdst, Rsrc1, imm* + +**Operands:** + - *Rdst* - Register R[0..3] + - *Rsrc1* - Register R[0..3] + - *Rsrc2* - Register R[0..3] + - *Imm* - 16-bit signed value + +**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:**:: + + 1: SUB R1, R2, R3 //R1 = R2 - R3 + + 2: sub R1, R2, 0x1234 //R1 = R2 - 0x1234 + + 3: .set value1, 0x03 //constant value1=0x03 + SUB R1, R2, value1 //R1 = R2 - value1 + 4: .global label //declaration of variable label + SUB R1, R2, label //R1 = R2 - label + .... + label: nop //definition of variable label + + +**AND** - Logical AND of two operands +------------------------------------- + +**Syntax:** + **AND** *Rdst, Rsrc1, Rsrc2* + + **AND** *Rdst, Rsrc1, imm* + +**Operands:** + - *Rdst* - Register R[0..3] + - *Rsrc1* - Register R[0..3] + - *Rsrc2* - Register R[0..3] + - *Imm* - 16-bit signed value + +**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**:: + + 1: AND R1, R2, R3 //R1 = R2 & R3 + + 2: AND R1, R2, 0x1234 //R1 = R2 & 0x1234 + + 3: .set value1, 0x03 //constant value1=0x03 + AND R1, R2, value1 //R1 = R2 & value1 + + 4: .global label //declaration of variable label + AND R1, R2, label //R1 = R2 & label + ... + label: nop //definition of variable label + + +**OR** - Logical OR of two operands +----------------------------------- + +**Syntax** + **OR** *Rdst, Rsrc1, Rsrc2* + + **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 + +**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. + +**Examples**:: + + 1: OR R1, R2, R3 //R1 = R2 \| R3 + + 2: OR R1, R2, 0x1234 //R1 = R2 \| 0x1234 + + 3: .set value1, 0x03 //constant value1=0x03 + OR R1, R2, value1 //R1 = R2 \| value1 + + 4: .global label //declaration of variable label + OR R1, R2, label //R1 = R2 \|label + ... + label: nop //definition of variable label + + + +**LSH** - Logical Shift Left +---------------------------- + +**Syntax** + **LSH** *Rdst, Rsrc1, Rsrc2* + + **LSH** *Rdst, Rsrc1, imm* + +**Operands** + - *Rdst* - Register R[0..3] + - *Rsrc1* - Register R[0..3] + - *Rsrc2* - Register R[0..3] + - *Imm* - 16-bit signed value + +**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. + +**Examples**:: + + 1: LSH R1, R2, R3 //R1 = R2 << R3 + + 2: LSH R1, R2, 0x03 //R1 = R2 << 0x03 + + 3: .set value1, 0x03 //constant value1=0x03 + LSH R1, R2, value1 //R1 = R2 << value1 + + 4: .global label //declaration of variable label + LSH R1, R2, label //R1 = R2 << label + ... + label: nop //definition of variable label + + +**RSH** - Logical Shift Right +---------------------------- + +**Syntax** + **RSH** *Rdst, Rsrc1, Rsrc2* + + **RSH** *Rdst, Rsrc1, imm* + +**Operands** + *Rdst* - Register R[0..3] + *Rsrc1* - Register R[0..3] + *Rsrc2* - Register R[0..3] + *Imm* - 16-bit signed value + +**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. + +**Examples**:: + + 1: RSH R1, R2, R3 //R1 = R2 >> R3 + + 2: RSH R1, R2, 0x03 //R1 = R2 >> 0x03 + + 3: .set value1, 0x03 //constant value1=0x03 + RSH R1, R2, value1 //R1 = R2 >> value1 + + 4: .global label //declaration of variable label + RSH R1, R2, label //R1 = R2 >> label + label: nop //definition of variable label + + + +**MOVE** – Move to register +--------------------------- + +**Syntax** + **MOVE** *Rdst, Rsrc* + + **MOVE** *Rdst, imm* + +**Operands** + - *Rdst* – Register R[0..3] + - *Rsrc* – Register R[0..3] + - *Imm* – 16-bit signed value + +**Description** + The instruction move to destination register value from source register or 16-bit signed value. + + Note that when a label is used as an immediate, the address of the label will be converted from bytes to words. This is because LD, ST, and JUMP instructions expect the address register value to be expressed in words rather than bytes. To avoid using an extra instruction + + +**Examples**:: + + 1: MOVE R1, R2 //R1 = R2 >> R3 + + 2: MOVE R1, 0x03 //R1 = R2 >> 0x03 + + 3: .set value1, 0x03 //constant value1=0x03 + MOVE R1, value1 //R1 = value1 + + 4: .global label //declaration of label + MOVE R1, label //R1 = address_of(label) / 4 + ... + label: nop //definition of label + + +**ST** – Store data to the memory +--------------------------------- + +**Syntax** + **ST** *Rsrc, Rdst, offset* + +**Operands** + - *Rsrc* – Register R[0..3], holds the 16-bit value to store + - *Rdst* – Register R[0..3], address of the destination, in 32-bit words + - *Offset* – 10-bit signed value, offset in bytes + +**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:: + + Mem[Rdst + offset / 4]{31:0} = {PC[10:0], 5'b0, Rsrc[15:0]} + + The application can use higher 16 bits to determine which instruction in the ULP program has written any particular word into memory. + +**Examples**:: + + 1: ST R1, R2, 0x12 //MEM[R2+0x12] = R1 + + 2: .data //Data section definition + Addr1: .word 123 // Define label Addr1 16 bit + .set offs, 0x00 // Define constant offs + .text //Text section definition + MOVE R1, 1 // R1 = 1 + MOVE R2, Addr1 // R2 = Addr1 + ST R1, R2, offs // MEM[R2 + 0] = R1 + // MEM[Addr1 + 0] will be 32'h600001 + + +**LD** – Load data from the memory +---------------------------------- + +**Syntax** + **LD** *Rdst, Rsrc, offset* + +**Operands** + *Rdst* – Register R[0..3], destination + + *Rsrc* – Register R[0..3], holds address of destination, in 32-bit words + + *Offset* – 10-bit signed value, offset in bytes + +**Description** + The instruction loads lower 16-bit half-word from memory with address Rsrc+offset into the destination register Rdst:: + + Rdst[15:0] = Mem[Rsrc + offset / 4][15:0] + +**Examples**:: + + 1: LD R1, R2, 0x12 //R1 = MEM[R2+0x12] + + 2: .data //Data section definition + Addr1: .word 123 // Define label Addr1 16 bit + .set offs, 0x00 // Define constant offs + .text //Text section definition + MOVE R1, 1 // R1 = 1 + MOVE R2, Addr1 // R2 = Addr1 / 4 (address of label is converted into words) + LD R1, R2, offs // R1 = MEM[R2 + 0] + // R1 will be 123 + + + + +**JUMP** – Jump to an absolute address +-------------------------------------- + +**Syntax** + **JUMP** *Rdst* + + **JUMP** *ImmAddr* + + **JUMP** *Rdst, Condition* + + **JUMP** *ImmAddr, Condition* + + +**Operands** + - *Rdst* – Register R[0..3] containing address to jump to (expressed in 32-bit words) + + - *ImmAddr* – 13 bits address (expressed in bytes), aligned to 4 bytes + + - *Condition*: + - EQ – jump if last ALU operation result was zero + - OV – jump if last ALU has set overflow flag + + +**Description** + The instruction makes jump to the specified address. Jump can be either unconditional or based on an ALU flag. + +**Examples**:: + + 1: JUMP R1 // Jump to address in R1 (address in R1 is in 32-bit words) + + 2: JUMP 0x120, EQ // Jump to address 0x120 (in bytes) if ALU result is zero + + 3: JUMP label // Jump to label + ... + label: nop // Definition of label + + 4: .global label // Declaration of global label + + MOVE R1, label // R1 = label (value loaded into R1 is in words) + JUMP R1 // Jump to label + ... + label: nop // Definition of label + + + +**JUMPR** – Jump to a relative offset (condition based on R0) +------------------------------------------------------------- + +**Syntax** + **JUMPR** *Step, Threshold, Condition* + +**Operands** + - *Step* – relative shift from current position, in bytes + - *Threshold* – threshold value for branch condition + - *Condition*: + - *GE* (greater or equal) – jump if value in R0 >= threshold + + - *LT* (less than) – jump if value in R0 < threshold + +**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. + +**Examples**:: + + 1:pos: JUMPR 16, 20, GE // Jump to address (position + 16 bytes) if value in R0 >= 20 + + 2: // Down counting loop using R0 register + MOVE R0, 16 // load 16 into R0 + label: SUB R0, R0, 1 // R0-- + NOP // do something + JUMPR label, 1, GE // jump to label if R0 >= 1 + + + +**JUMPS** – Jump to a relative address (condition based on stage count) +----------------------------------------------------------------------- + +**Syntax** + **JUMPS** *Step, Threshold, Condition* + +**Operands** + - *Step* – relative shift from current position, in bytes + - *Threshold* – threshold value for branch condition + - *Condition*: + - *EQ* (equal) – jump if value in stage_cnt == threshold + - *LT* (less than) – jump if value in stage_cnt < threshold + - *GT* (greater than) – jump if value in stage_cnt > threshold + +**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. + +**Examples**:: + + 1:pos: JUMPS 16, 20, EQ // Jump to (position + 16 bytes) if stage_cnt == 20 + + 2: // Up counting loop using stage count register + STAGE_RST // set stage_cnt to 0 + label: STAGE_INC 1 // stage_cnt++ + NOP // do something + JUMPS label, 16, LT // jump to label if stage_cnt < 16 + + + +**STAGE_RST** – Reset stage count register +------------------------------------------ +**Syntax** + **STAGE_RST** + +**Operands** + No operands + +**Description** + The instruction sets the stage count register to 0 + +**Examples**:: + + 1: STAGE_RST // Reset stage count register + + + +**STAGE_INC** – Increment stage count register +---------------------------------------------- + +**Syntax** + **STAGE_INC** *Value* + +**Operands** + - *Value* – 8 bits value + +**Description** + The instruction increments stage count register by given value. + +**Examples**:: + + 1: STAGE_INC 10 // stage_cnt += 10 + + 2: // Up counting loop example: + STAGE_RST // set stage_cnt to 0 + label: STAGE_INC 1 // stage_cnt++ + NOP // do something + JUMPS label, 16, LT // jump to label if stage_cnt < 16 + + +**STAGE_DEC** – Decrement stage count register +---------------------------------------------- + +**Syntax** + **STAGE_DEC** *Value* + +**Operands** + - *Value* – 8 bits value + +**Description** + The instruction decrements stage count register by given value. + +**Examples**:: + + 1: STAGE_DEC 10 // stage_cnt -= 10; + + 2: // Down counting loop exaple + STAGE_RST // set stage_cnt to 0 + STAGE_INC 16 // increment stage_cnt to 16 + label: STAGE_DEC 1 // stage_cnt--; + NOP // do something + JUMPS label, 0, GT // jump to label if stage_cnt > 0 + + +**HALT** – End the program +-------------------------- + +**Syntax** + **HALT** + +**Operands** + No operands +**Description** + The instruction halt the processor to the power down mode + +**Examples**:: + + 1: HALT // Move chip to powerdown + + + +**WAKE** – wakeup the chip +-------------------------- + +**Syntax** + **WAKE** + +**Operands** + No operands + +**Description** + The instruction sends an interrupt from ULP to RTC controller. + + - If the SoC is in deep sleep mode, and ULP wakeup is enabled, this causes the SoC to wake up. + + - 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. + +**Examples**:: + + 1: 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, + // and ULP will not run again until started by the main program. + + + +**SLEEP** – set ULP wakeup timer period +--------------------------------------- + +**Syntax** + **SLEEP** *sleep_reg* + +**Operands** + - *sleep_reg* – 0..4, selects one of ``SENS_ULP_CP_SLEEP_CYCx_REG`` registers. + +**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. + +**Examples**:: + + 1: SLEEP 1 // Use period set in SENS_ULP_CP_SLEEP_CYC1_REG + + 2: .set sleep_reg, 4 // Set constant + SLEEP sleep_reg // Use period set in SENS_ULP_CP_SLEEP_CYC4_REG + + +**WAIT** – wait some number of cycles +------------------------------------- + +**Syntax** + **WAIT** *Cycles* + +**Operands** + - *Cycles* – number of cycles for wait + +**Description** + The instruction delays for given number of cycles. + +**Examples**:: + + 1: WAIT 10 // Do nothing for 10 cycles + + 2: .set wait_cnt, 10 // Set a constant + WAIT wait_cnt // wait for 10 cycles + + + + +**TSENS** – do measurement with temperature sensor +-------------------------------------------------- + +**Syntax** + - **TSENS** *Rdst, Wait_Delay* + +**Operands** + - *Rdst* – Destination Register R[0..3], result will be stored to this register + - *Wait_Delay* – number of cycles used to perform the measurement + + +**Description** + The instruction performs measurement using TSENS and stores the result into a general purpose register. + +**Examples**:: + + 1: TSENS R1, 1000 // Measure temperature sensor for 1000 cycles, + // and store result to R1 + + + + +**ADC** – do measurement with ADC +--------------------------------- + +**Syntax** + **ADC** *Rdst, Sar_sel, Mux, Cycles* + +**Operands** + - *Rdst* – Destination Register R[0..3], result will be stored to this register + - *Sar_sel* – selected ADC : 0=SARADC0, 1=SARADC1 + - *Mux* - selected PAD, SARADC Pad[Mux+1] is enabled + - *Cycle* – number of cycles used to perform measurement + +**Description** + The instruction makes measurements from ADC. + +**Examples**:: + + 1: ADC R1, 0, 1, 100 // Measure value using ADC1 pad 2, + // for 100 cycles and move result to R1 + + +**REG_RD** – read from peripheral register +------------------------------------------ + +**Syntax** + **REG_RD** *Addr, High, Low* + +**Operands** + - *Addr* – register address, in 32-bit words + - *High* – High part of R0 + - *Low* – Low part of R0 + +**Description** + The instruction reads up to 16 bits from a peripheral register into a general purpose register: ``R0 = REG[Addr][High:Low]``. + + This instruction can access registers in RTC_CNTL, RTC_IO, and SENS peripherals. Address of the the register, as seen from the ULP, + can be calculated from the address of the same register on the DPORT bus as follows:: + + addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4 + +**Examples**:: + + 1: REG_RD 0x120, 2, 0 // load 4 bits: R0 = {12'b0, REG[0x120][7:4]} + + +**REG_WR** – write to peripheral register +----------------------------------------- + +**Syntax** + **REG_WR** *Addr, High, Low, Data* + +**Operands** + - *Addr* – register address, in 32-bit words. + - *High* – High part of R0 + - *Low* – Low part of R0 + - *Data* – value to write, 8 bits + +**Description** + The instruction writes up to 8 bits from a general purpose register into a peripheral register. ``REG[Addr][High:Low] = data`` + + This instruction can access registers in RTC_CNTL, RTC_IO, and SENS peripherals. Address of the the register, as seen from the ULP, + can be calculated from the address of the same register on the DPORT bus as follows:: + + addr_ulp = (addr_dport - DR_REG_RTCCNTL_BASE) / 4 + +**Examples**:: + + 1: REG_WR 0x120, 7, 0, 0x10 // set 8 bits: REG[0x120][7:0] = 0x10 + +Convenience macros for peripheral registers access +-------------------------------------------------- + +ULP source files are passed through C preprocessor before the assembler. This allows certain macros to be used to facilitate access to peripheral registers. + +Some existing macros are defined in ``soc/soc_ulp.h`` header file. These macros allow access to the fields of peripheral registers by their names. +Peripheral registers names which can be used with these macros are the ones defined in ``soc/rtc_cntl_reg.h``, ``soc/rtc_io_reg.h``, and ``soc/sens_reg.h``. + +READ_RTC_REG(rtc_reg, low_bit, bit_width) + Read up to 16 bits from rtc_reg[low_bit + bit_width - 1 : low_bit] into R0. For example:: + + #include "soc/soc_ulp.h" + #include "soc/rtc_cntl_reg.h" + + /* Read 16 lower bits of RTC_CNTL_TIME0_REG into R0 */ + READ_RTC_REG(RTC_CNTL_TIME0_REG, 0, 16) + +READ_RTC_FIELD(rtc_reg, field) + Read from a field in rtc_reg into R0, up to 16 bits. For example:: + + #include "soc/soc_ulp.h" + #include "soc/sens_reg.h" + + /* Read 8-bit SENS_TSENS_OUT field of SENS_SAR_SLAVE_ADDR3_REG into R0 */ + READ_RTC_REG(SENS_SAR_SLAVE_ADDR3_REG, SENS_TSENS_OUT) + +WRITE_RTC_REG(rtc_reg, low_bit, bit_width, value) + Write immediate value into rtc_reg[low_bit + bit_width - 1 : low_bit], bit_width <= 8. For example:: + + #include "soc/soc_ulp.h" + #include "soc/rtc_io_reg.h" + + /* Set BIT(2) of RTC_GPIO_OUT_DATA_W1TS field in RTC_GPIO_OUT_W1TS_REG */ + WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + 2, 1, 1) + + +WRITE_RTC_FIELD(rtc_reg, field, value) + Write immediate value into a field in rtc_reg, up to 8 bits. For example:: + + #include "soc/soc_ulp.h" + #include "soc/rtc_cntl_reg.h" + + /* Set RTC_CNTL_ULP_CP_SLP_TIMER_EN field of RTC_CNTL_STATE0_REG to 0 */ + READ_RTC_REG(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0) + + + + + + diff --git a/docs/ulp_macros.rst b/docs/ulp_macros.rst new file mode 100644 index 000000000..2e3d2a07a --- /dev/null +++ b/docs/ulp_macros.rst @@ -0,0 +1 @@ +.. include:: ../components/ulp/README.rst \ No newline at end of file diff --git a/examples/system/ulp/Makefile b/examples/system/ulp/Makefile new file mode 100644 index 000000000..bb046de35 --- /dev/null +++ b/examples/system/ulp/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ulp-example + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/system/ulp/README.md b/examples/system/ulp/README.md new file mode 100644 index 000000000..a965736d5 --- /dev/null +++ b/examples/system/ulp/README.md @@ -0,0 +1,50 @@ +# ULP Pulse Counting Example + +This example demonstrates how to program the ULP coprocessor to count pulses on an IO while the main CPUs are either running some other code or are in deep sleep. See the README.md file in the upper level 'examples' directory for more information about examples. + +ULP program written in assembly can be found in `ulp/pulse_cnt.S`. The build system assembles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application. + +At runtime, the main code running on the ESP32 (found in main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_run`. Once the ULP program is started, it runs periodically, with the period set by the main program. The main program enables ULP wakeup source and puts the chip into deep sleep mode. + +When the ULP program finds an edge in the input signal, it performs debouncing and increments the variable maintaining the total edge count. Once the edge count reaches certain value (set by the main program), ULP triggers wake up from deep sleep. Note that the ULP program keeps running and monitoring the input signal even when the SoC is woken up. + +Upon wakeup, the main program saves total edge count into NVS and returns to deep sleep. + +In this example the input signal is connected to GPIO0. Note that this pin was chosen because most development boards have a button connected to it, so the pulses to be counted can be generated by pressing the button. For real world applications this is not a good choice of a pin, because GPIO0 also acts as a bootstrapping pin. To change the pin number, check the ESP32 Chip Pin List document and adjust `gpio_num` and `ulp_io_number` variables in main.c. + +## Example output + +Note: GPIO15 is connected to GND to disable ROM bootloader output. + +``` +Not ULP wakeup, initializing ULP +Entering deep sleep + +ULP wakeup, saving pulse count +Read pulse count from NVS: 384 +Pulse count from ULP: 5 +Wrote updated pulse count to NVS: 389 +Entering deep sleep + +ULP wakeup, saving pulse count +Read pulse count from NVS: 389 +Pulse count from ULP: 5 +Wrote updated pulse count to NVS: 394 +Entering deep sleep + +ULP wakeup, saving pulse count +Read pulse count from NVS: 394 +Pulse count from ULP: 6 +Wrote updated pulse count to NVS: 400 +Entering deep sleep + +ULP wakeup, saving pulse count +Read pulse count from NVS: 400 +Pulse count from ULP: 5 +Wrote updated pulse count to NVS: 405 +Entering deep sleep +``` + +Note that in one case the pulse count captured by the ULP program is 6, even though the `edge_count_to_wake_up` variable is set to 10 by the main program. This shows that the ULP program keeps track of pulses while the main CPUs are starting up, so when pulses are sent rapidly it is possible to register more pulses between wake up and entry into app_main. + + \ No newline at end of file diff --git a/examples/system/ulp/main/component.mk b/examples/system/ulp/main/component.mk new file mode 100644 index 000000000..566757a56 --- /dev/null +++ b/examples/system/ulp/main/component.mk @@ -0,0 +1,25 @@ + + +# +# ULP support additions to component makefile. +# +# 1. ULP_APP_NAME must be unique (if multiple components use ULP) +# Default value, override if necessary: +ULP_APP_NAME ?= ulp_$(COMPONENT_NAME) +# +# 2. Specify all assembly source files here. +# Files should be placed into a separate directory (in this case, ulp/), +# which should not be added to COMPONENT_SRCDIRS. +ULP_S_SOURCES = $(addprefix $(COMPONENT_PATH)/ulp/, \ + pulse_cnt.S \ + ) +# +# 3. List all the component object files which include automatically +# generated ULP export file, $(ULP_APP_NAME).h: +ULP_EXP_DEP_OBJECTS := ulp_example_main.o +# +# 4. Include build rules for ULP program +include $(IDF_PATH)/components/ulp/component_ulp_common.mk +# +# End of ULP support additions to component makefile. +# diff --git a/examples/system/ulp/main/ulp/pulse_cnt.S b/examples/system/ulp/main/ulp/pulse_cnt.S new file mode 100644 index 000000000..ba7b45344 --- /dev/null +++ b/examples/system/ulp/main/ulp/pulse_cnt.S @@ -0,0 +1,135 @@ +/* ULP Example: pulse counting + + 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. + + This file contains assembly code which runs on the ULP. + + ULP wakes up to run this code at a certain period, determined by the values + in SENS_ULP_CP_SLEEP_CYCx_REG registers. On each wake up, the program checks + the input on GPIO0. If the value is different from the previous one, the + program "debounces" the input: on the next debounce_max_count wake ups, + it expects to see the same value of input. + If this condition holds true, the program increments edge_count and starts + waiting for input signal polarity to change again. + When the edge counter reaches certain value (set by the main program), + this program running triggers a wake up from deep sleep. +*/ + +/* ULP assembly files are passed through C preprocessor first, so include directives + and C macros may be used in these files + */ +#include "soc/rtc_cntl_reg.h" +#include "soc/rtc_io_reg.h" +#include "soc/soc_ulp.h" + + /* Define variables, which go into .bss section (zero-initialized data) */ + .bss + /* Next input signal edge expected: 0 (negative) or 1 (positive) */ + .global next_edge +next_edge: + .long 0 + + /* Counter started when signal value changes. + Edge is "debounced" when the counter reaches zero. */ + .global debounce_counter +debounce_counter: + .long 0 + + /* Value to which debounce_counter gets reset. + Set by the main program. */ + .global debounce_max_count +debounce_max_count: + .long 0 + + /* Total number of signal edges acquired */ + .global edge_count +edge_count: + .long 0 + + /* Number of edges to acquire before waking up the SoC. + Set by the main program. */ + .global edge_count_to_wake_up +edge_count_to_wake_up: + .long 0 + + /* RTC IO number used to sample the input signal. + Set by main program. */ + .global io_number +io_number: + .long 0 + + /* Code goes into .text section */ + .text + .global entry +entry: + /* Read the value of lower 16 RTC IOs into R0 */ + READ_RTC_FIELD(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT) + /* Load io_number, extract the state of input */ + move r3, io_number + ld r3, r3, 0 + rsh r0, r0, r3 + and r0, r0, 1 + /* State of input changed? */ + move r3, next_edge + ld r3, r3, 0 + add r3, r0, r3 + and r3, r3, 1 + jump changed, eq + /* Not changed */ + /* Reset debounce_counter to debounce_max_count */ + move r3, debounce_max_count + move r2, debounce_counter + ld r3, r3, 0 + st r3, r2, 0 + /* End program */ + halt + + .global changed +changed: + /* Input state changed */ + /* Has debounce_counter reached zero? */ + move r3, debounce_counter + ld r2, r3, 0 + add r2, r2, 0 /* dummy ADD to use "jump if ALU result is zero" */ + jump edge_detected, eq + /* Not yet. Decrement debounce_counter */ + sub r2, r2, 1 + st r2, r3, 0 + /* End program */ + halt + + .global edge_detected +edge_detected: + /* Reset debounce_counter to debounce_max_count */ + move r3, debounce_max_count + move r2, debounce_counter + ld r3, r3, 0 + st r3, r2, 0 + /* Flip next_edge */ + move r3, next_edge + ld r2, r3, 0 + add r2, r2, 1 + and r2, r2, 1 + st r2, r3, 0 + /* Increment edge_count */ + move r3, edge_count + ld r2, r3, 0 + add r2, r2, 1 + st r2, r3, 0 + /* Compare edge_count to edge_count_to_wake_up */ + move r3, edge_count_to_wake_up + ld r3, r3, 0 + sub r3, r3, r2 + jump wake_up, eq + /* Not yet. End program */ + halt + + .global wake_up +wake_up: + /* Wake up the SoC, end program */ + wake + halt diff --git a/examples/system/ulp/main/ulp_example_main.c b/examples/system/ulp/main/ulp_example_main.c new file mode 100644 index 000000000..3277c12c2 --- /dev/null +++ b/examples/system/ulp/main/ulp_example_main.c @@ -0,0 +1,106 @@ +/* ULP 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 +#include "esp_deep_sleep.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/sens_reg.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "esp32/ulp.h" +#include "ulp_main.h" + +extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); +extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); + +static void init_ulp_program(); +static void update_pulse_count(); + +void app_main() +{ + esp_deep_sleep_wakeup_cause_t cause = esp_deep_sleep_get_wakeup_cause(); + if (cause != ESP_DEEP_SLEEP_WAKEUP_ULP) { + printf("Not ULP wakeup, initializing ULP\n"); + init_ulp_program(); + } else { + printf("ULP wakeup, saving pulse count\n"); + update_pulse_count(); + } + + printf("Entering deep sleep\n\n"); + ESP_ERROR_CHECK( esp_deep_sleep_enable_ulp_wakeup() ); + esp_deep_sleep_start(); +} + +static void init_ulp_program() +{ + esp_err_t err = ulp_load_binary(0, ulp_main_bin_start, + (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); + ESP_ERROR_CHECK(err); + + /* Initialize some variables used by ULP program. + * Each 'ulp_xyz' variable corresponds to 'xyz' variable in the ULP program. + * These variables are declared in an auto generated header file, + * 'ulp_main.h', name of this file is defined in component.mk as ULP_APP_NAME. + * These variables are located in RTC_SLOW_MEM and can be accessed both by the + * ULP and the main CPUs. + * + * Note that the ULP reads only the lower 16 bits of these variables. + */ + ulp_debounce_counter = 3; + ulp_debounce_max_count = 3; + ulp_next_edge = 0; + ulp_io_number = 11; /* GPIO0 is RTC_IO 11 */ + ulp_edge_count_to_wake_up = 10; + + /* Initialize GPIO0 as RTC IO, input, disable pullup and pulldown */ + gpio_num_t gpio_num = GPIO_NUM_0; + rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_dis(gpio_num); + rtc_gpio_pullup_dis(gpio_num); + rtc_gpio_hold_en(gpio_num); + + /* Set ULP wake up period to T = 20ms (3095 cycles of RTC_SLOW_CLK clock). + * Minimum pulse width has to be T * (ulp_debounce_counter + 1) = 80ms. + */ + REG_SET_FIELD(SENS_ULP_CP_SLEEP_CYC0_REG, SENS_SLEEP_CYCLES_S0, 3095); + + /* Start the program */ + err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)); + ESP_ERROR_CHECK(err); +} + +static void update_pulse_count() +{ + const char* namespace = "plusecnt"; + const char* count_key = "count"; + + ESP_ERROR_CHECK( nvs_flash_init() ); + nvs_handle handle; + ESP_ERROR_CHECK( nvs_open(namespace, NVS_READWRITE, &handle)); + uint32_t pulse_count = 0; + esp_err_t err = nvs_get_u32(handle, count_key, &pulse_count); + assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); + printf("Read pulse count from NVS: %5d\n", pulse_count); + + /* ULP program counts signal edges, convert that to the number of pulses */ + uint32_t pulse_count_from_ulp = (ulp_edge_count & UINT16_MAX) / 2; + /* In case of an odd number of edges, keep one until next time */ + ulp_edge_count = ulp_edge_count % 2; + printf("Pulse count from ULP: %5d\n", pulse_count_from_ulp); + + /* Save the new pulse count to NVS */ + pulse_count += pulse_count_from_ulp; + ESP_ERROR_CHECK(nvs_set_u32(handle, count_key, pulse_count)); + ESP_ERROR_CHECK(nvs_commit(handle)); + nvs_close(handle); + printf("Wrote updated pulse count to NVS: %5d\n", pulse_count); +} diff --git a/examples/system/ulp/sdkconfig.defaults b/examples/system/ulp/sdkconfig.defaults new file mode 100644 index 000000000..0ce9dc763 --- /dev/null +++ b/examples/system/ulp/sdkconfig.defaults @@ -0,0 +1,11 @@ +# Enable ULP +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_RESERVE_MEM=1024 +# Some flash chips need extra time to wake up +# Set this a bit higher to improve out-of-the-box experience +CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=500 +# Set log level to Warning to produce clean output +CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y +CONFIG_LOG_BOOTLOADER_LEVEL=2 +CONFIG_LOG_DEFAULT_LEVEL_WARN=y +CONFIG_LOG_DEFAULT_LEVEL=2 From 821c70f5d7df7ffcfaaa013dba60cc9c38b43512 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 22 Mar 2017 12:36:11 +0800 Subject: [PATCH 49/57] examples: Standardise naming of files, symbols, etc. in examples * Use "example" in all example function & variable names, ie use i2c_example_xxx instead of i2c_xxx for example functions. Closes #198 https://github.com/espressif/esp-idf/issues/198 * Mark example functions, etc. static * Replace uses of "test" & "demo" with "example" * Split the UART example into two * Rename "main" example files to end with "_main.c" for disambiguation --- examples/README.md | 3 + .../main/{blufi_demo.h => blufi_example.h} | 12 +- .../{blufi_main.c => blufi_example_main.c} | 36 +- .../bluetooth/blufi/main/blufi_security.c | 2 +- ...thernet_main.c => ethernet_example_main.c} | 2 +- .../main/{gpio_test.c => gpio_example_main.c} | 6 +- .../main/{i2c_test.c => i2c_example_main.c} | 74 ++-- .../main/{app_main.c => i2s_example_main.c} | 0 .../main/{ledc_fade.c => ledc_example_main.c} | 0 .../main/{pcnt_test.c => pcnt_example_main.c} | 8 +- examples/peripherals/rmt_nec_tx_rx/README.md | 4 +- .../rmt_nec_tx_rx/main/infrared_nec.c | 358 ------------------ .../rmt_nec_tx_rx/main/infrared_nec_main.c | 353 ++++++++++++++++- ...delta_test.c => sigmadelta_example_main.c} | 4 +- ...spi_master.c => spi_master_example_main.c} | 6 +- ...mer_group.c => timer_group_example_main.c} | 12 +- .../main/tp_interrupt_main.c | 20 +- .../touch_pad_read/main/tp_read_main.c | 4 +- .../peripherals/{uart => uart_echo}/Makefile | 2 +- .../{uart => uart_echo}/main/component.mk | 0 .../uart_echo/main/uart_echo_example_main.c | 73 ++++ examples/peripherals/uart_events/Makefile | 9 + .../peripherals/uart_events/main/component.mk | 3 + .../main/uart_events_example_main.c} | 99 ++--- ...ap_client.c => coap_client_example_main.c} | 4 +- ...ap_server.c => coap_server_example_main.c} | 4 +- ...est_main.c => http_request_example_main.c} | 0 ...st_main.c => https_request_example_main.c} | 0 .../protocols/mdns/main/mdns_example_main.c | 4 +- ...nssl_client.h => openssl_client_example.h} | 24 +- ...client.c => openssl_client_example_main.c} | 42 +- ...nssl_server.h => openssl_server_example.h} | 10 +- ...server.c => openssl_server_example_main.c} | 32 +- .../main/{sntp_main.c => sntp_example_main.c} | 0 ...{nvs_rw_blob.c => nvs_blob_example_main.c} | 0 ...vs_rw_value.c => nvs_value_example_main.c} | 0 .../{sd_card.c => sd_card_example_main.c} | 0 ...eep_wakeup.c => deep_sleep_example_main.c} | 0 .../{ota_example.c => ota_example_main.c} | 8 +- .../main/wpa2_enterprise_main.c | 4 +- 40 files changed, 624 insertions(+), 598 deletions(-) rename examples/bluetooth/blufi/main/{blufi_demo.h => blufi_example.h} (59%) rename examples/bluetooth/blufi/main/{blufi_main.c => blufi_example_main.c} (91%) rename examples/ethernet/ethernet/main/{ethernet_main.c => ethernet_example_main.c} (99%) rename examples/peripherals/gpio/main/{gpio_test.c => gpio_example_main.c} (96%) rename examples/peripherals/i2c/main/{i2c_test.c => i2c_example_main.c} (77%) rename examples/peripherals/i2s/main/{app_main.c => i2s_example_main.c} (100%) rename examples/peripherals/ledc/main/{ledc_fade.c => ledc_example_main.c} (100%) rename examples/peripherals/pcnt/main/{pcnt_test.c => pcnt_example_main.c} (97%) delete mode 100644 examples/peripherals/rmt_nec_tx_rx/main/infrared_nec.c rename examples/peripherals/sigmadelta/main/{sigmadelta_test.c => sigmadelta_example_main.c} (95%) rename examples/peripherals/spi_master/main/{spi_master.c => spi_master_example_main.c} (98%) rename examples/peripherals/timer_group/main/{timer_group.c => timer_group_example_main.c} (96%) rename examples/peripherals/{uart => uart_echo}/Makefile (85%) rename examples/peripherals/{uart => uart_echo}/main/component.mk (100%) create mode 100644 examples/peripherals/uart_echo/main/uart_echo_example_main.c create mode 100644 examples/peripherals/uart_events/Makefile create mode 100644 examples/peripherals/uart_events/main/component.mk rename examples/peripherals/{uart/main/uart_test.c => uart_events/main/uart_events_example_main.c} (57%) rename examples/protocols/coap_client/main/{coap_client.c => coap_client_example_main.c} (98%) rename examples/protocols/coap_server/main/{coap_server.c => coap_server_example_main.c} (98%) rename examples/protocols/http_request/main/{http_request_main.c => http_request_example_main.c} (100%) rename examples/protocols/https_request/main/{https_request_main.c => https_request_example_main.c} (100%) rename examples/protocols/openssl_client/main/{openssl_client.h => openssl_client_example.h} (56%) rename examples/protocols/openssl_client/main/{openssl_client.c => openssl_client_example_main.c} (82%) rename examples/protocols/openssl_server/main/{openssl_server.h => openssl_server_example.h} (75%) rename examples/protocols/openssl_server/main/{openssl_server.c => openssl_server_example_main.c} (88%) rename examples/protocols/sntp/main/{sntp_main.c => sntp_example_main.c} (100%) rename examples/storage/nvs_rw_blob/main/{nvs_rw_blob.c => nvs_blob_example_main.c} (100%) rename examples/storage/nvs_rw_value/main/{nvs_rw_value.c => nvs_value_example_main.c} (100%) rename examples/storage/sd_card/main/{sd_card.c => sd_card_example_main.c} (100%) rename examples/system/deep_sleep/main/{deep_sleep_wakeup.c => deep_sleep_example_main.c} (100%) rename examples/system/ota/main/{ota_example.c => ota_example_main.c} (97%) diff --git a/examples/README.md b/examples/README.md index e4422e91b..ead17f0b7 100644 --- a/examples/README.md +++ b/examples/README.md @@ -32,4 +32,7 @@ In addition, here are some tips for creating good examples: * A good example is documented and the basic options can be configured. * A good example does not contain a lot of code. If there is a lot of generic code in the example, consider refactoring that code into a standalone component and then use the component's API in your example. +* Names (of files, functions, variables, etc.) inside examples should be distinguishable from names of other parts of IDF (ideally, use `example` in names.) +* Functions and variables used inside examples should be declared static where possible. +* Examples should demonstrate one distinct thing each. Avoid multi-purposed "demo" examples, split these into multiple examples instead. * Examples must be licensed under the Apache License 2.0 or (preferably for examples) if possible you can declare the example to be Public Domain / Creative Commons Zero. diff --git a/examples/bluetooth/blufi/main/blufi_demo.h b/examples/bluetooth/blufi/main/blufi_example.h similarity index 59% rename from examples/bluetooth/blufi/main/blufi_demo.h rename to examples/bluetooth/blufi/main/blufi_example.h index c5bf55c7d..955e238c7 100644 --- a/examples/bluetooth/blufi/main/blufi_demo.h +++ b/examples/bluetooth/blufi/main/blufi_example.h @@ -1,10 +1,8 @@ -#ifndef __BLUFI_DEMO_H__ -#define __BLUFI_DEMO_H__ +#pragma once - -#define BLUFI_DEMO_TAG "BLUFI_DEMO" -#define BLUFI_INFO(fmt, ...) ESP_LOGI(BLUFI_DEMO_TAG, fmt, ##__VA_ARGS__) -#define BLUFI_ERROR(fmt, ...) ESP_LOGE(BLUFI_DEMO_TAG, fmt, ##__VA_ARGS__) +#define BLUFI_EXAMPLE_TAG "BLUFI_EXAMPLE" +#define BLUFI_INFO(fmt, ...) ESP_LOGI(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__) +#define BLUFI_ERROR(fmt, ...) ESP_LOGE(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__) void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free); int blufi_aes_encrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len); @@ -13,5 +11,3 @@ uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len); int blufi_security_init(void); void blufi_security_deinit(void); - -#endif /* __BLUFI_DEMO_H__ */ diff --git a/examples/bluetooth/blufi/main/blufi_main.c b/examples/bluetooth/blufi/main/blufi_example_main.c similarity index 91% rename from examples/bluetooth/blufi/main/blufi_main.c rename to examples/bluetooth/blufi/main/blufi_example_main.c index d35ab7121..05f39c485 100644 --- a/examples/bluetooth/blufi/main/blufi_main.c +++ b/examples/bluetooth/blufi/main/blufi_example_main.c @@ -30,19 +30,19 @@ #include "esp_gap_ble_api.h" #include "esp_bt_main.h" #include "esp_bt_device.h" -#include "blufi_demo.h" +#include "blufi_example.h" -static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param); +static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param); #define BLUFI_DEVICE_NAME "BLUFI_DEVICE" -static uint8_t blufi_service_uuid128[32] = { +static uint8_t example_service_uuid128[32] = { /* LSB <--------------------------------------------------------------------------------> MSB */ //first uuid, 16bit, [12],[13] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, }; //static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56}; -static esp_ble_adv_data_t blufi_adv_data = { +static esp_ble_adv_data_t example_adv_data = { .set_scan_rsp = false, .include_name = true, .include_txpower = true, @@ -54,11 +54,11 @@ static esp_ble_adv_data_t blufi_adv_data = { .service_data_len = 0, .p_service_data = NULL, .service_uuid_len = 16, - .p_service_uuid = blufi_service_uuid128, + .p_service_uuid = example_service_uuid128, .flag = 0x6, }; -static esp_ble_adv_params_t blufi_adv_params = { +static esp_ble_adv_params_t example_adv_params = { .adv_int_min = 0x100, .adv_int_max = 0x100, .adv_type = ADV_TYPE_IND, @@ -88,7 +88,7 @@ static uint8_t gl_sta_bssid[6]; static uint8_t gl_sta_ssid[32]; static int gl_sta_ssid_len; -static esp_err_t event_handler(void *ctx, system_event_t *event) +static esp_err_t example_net_event_handler(void *ctx, system_event_t *event) { wifi_mode_t mode; @@ -146,7 +146,7 @@ static void initialise_wifi(void) { tcpip_adapter_init(); wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); + ESP_ERROR_CHECK( esp_event_loop_init(example_net_event_handler, NULL) ); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); @@ -154,24 +154,24 @@ static void initialise_wifi(void) ESP_ERROR_CHECK( esp_wifi_start() ); } -static esp_blufi_callbacks_t blufi_callbacks = { - .event_cb = blufi_event_callback, +static esp_blufi_callbacks_t example_callbacks = { + .event_cb = example_event_callback, .negotiate_data_handler = blufi_dh_negotiate_data_handler, .encrypt_func = blufi_aes_encrypt, .decrypt_func = blufi_aes_decrypt, .checksum_func = blufi_crc_checksum, }; -static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param) +static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param) { /* actually, should post to blufi_task handle the procedure, - * now, as a demo, we do simplely */ + * now, as a example, we do it more simply */ switch (event) { case ESP_BLUFI_EVENT_INIT_FINISH: BLUFI_INFO("BLUFI init finish\n"); esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME); - esp_ble_gap_config_adv_data(&blufi_adv_data); + esp_ble_gap_config_adv_data(&example_adv_data); break; case ESP_BLUFI_EVENT_DEINIT_FINISH: BLUFI_INFO("BLUFI init finish\n"); @@ -184,7 +184,7 @@ static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_ break; case ESP_BLUFI_EVENT_BLE_DISCONNECT: BLUFI_INFO("BLUFI ble disconnect\n"); - esp_ble_gap_start_advertising(&blufi_adv_params); + esp_ble_gap_start_advertising(&example_adv_params); break; case ESP_BLUFI_EVENT_SET_WIFI_OPMODE: BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode); @@ -297,11 +297,11 @@ static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_ } } -static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +static void example_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: - esp_ble_gap_start_advertising(&blufi_adv_params); + esp_ble_gap_start_advertising(&example_adv_params); break; default: break; @@ -340,8 +340,8 @@ void app_main() BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version()); blufi_security_init(); - esp_ble_gap_register_callback(gap_event_handler); + esp_ble_gap_register_callback(example_gap_event_handler); - esp_blufi_register_callbacks(&blufi_callbacks); + esp_blufi_register_callbacks(&example_callbacks); esp_blufi_profile_init(); } diff --git a/examples/bluetooth/blufi/main/blufi_security.c b/examples/bluetooth/blufi/main/blufi_security.c index 59d889a52..1005c94c1 100644 --- a/examples/bluetooth/blufi/main/blufi_security.c +++ b/examples/bluetooth/blufi/main/blufi_security.c @@ -29,7 +29,7 @@ #include "esp_bt_defs.h" #include "esp_gap_ble_api.h" #include "esp_bt_main.h" -#include "blufi_demo.h" +#include "blufi_example.h" #include "mbedtls/aes.h" #include "mbedtls/dhm.h" diff --git a/examples/ethernet/ethernet/main/ethernet_main.c b/examples/ethernet/ethernet/main/ethernet_example_main.c similarity index 99% rename from examples/ethernet/ethernet/main/ethernet_main.c rename to examples/ethernet/ethernet/main/ethernet_example_main.c index f76bd1d76..d46e2e6d9 100644 --- a/examples/ethernet/ethernet/main/ethernet_main.c +++ b/examples/ethernet/ethernet/main/ethernet_example_main.c @@ -34,7 +34,7 @@ #include "driver/gpio.h" #include "tlk110_phy.h" -static const char *TAG = "eth_demo"; +static const char *TAG = "eth_example"; #define DEFAULT_PHY_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG) #define PIN_PHY_POWER 17 diff --git a/examples/peripherals/gpio/main/gpio_test.c b/examples/peripherals/gpio/main/gpio_example_main.c similarity index 96% rename from examples/peripherals/gpio/main/gpio_test.c rename to examples/peripherals/gpio/main/gpio_example_main.c index a5e9571bc..3b306ac14 100644 --- a/examples/peripherals/gpio/main/gpio_test.c +++ b/examples/peripherals/gpio/main/gpio_example_main.c @@ -41,13 +41,13 @@ static xQueueHandle gpio_evt_queue = NULL; -void IRAM_ATTR gpio_isr_handler(void* arg) +static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); } -void gpio_task_example(void* arg) +static void gpio_task_example(void* arg) { uint32_t io_num; for(;;) { @@ -62,7 +62,7 @@ void app_main() gpio_config_t io_conf; //disable interrupt io_conf.intr_type = GPIO_PIN_INTR_DISABLE; - //set as output mode + //set as output mode io_conf.mode = GPIO_MODE_OUTPUT; //bit mask of the pins that you want to set,e.g.GPIO18/19 io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; diff --git a/examples/peripherals/i2c/main/i2c_test.c b/examples/peripherals/i2c/main/i2c_example_main.c similarity index 77% rename from examples/peripherals/i2c/main/i2c_test.c rename to examples/peripherals/i2c/main/i2c_example_main.c index 2ef6d75b2..51f8dc47e 100644 --- a/examples/peripherals/i2c/main/i2c_test.c +++ b/examples/peripherals/i2c/main/i2c_example_main.c @@ -47,18 +47,18 @@ #define RW_TEST_LENGTH 129 /*! -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include "esp_err.h" -#include "esp_log.h" -#include "driver/rmt.h" -#include "driver/periph_ctrl.h" -#include "soc/rmt_reg.h" - -static const char* NEC_TAG = "NEC"; - -//CHOOSE SELF TEST OR NORMAL TEST -#define RMT_RX_SELF_TEST 1 - -/******************************************************/ -/***** SELF TEST: *****/ -/*Connect RMT_TX_GPIO_NUM with RMT_RX_GPIO_NUM */ -/*TX task will send NEC data with carrier disabled */ -/*RX task will print NEC data it receives. */ -/******************************************************/ -#if RMT_RX_SELF_TEST -#define RMT_RX_ACTIVE_LEVEL 1 /*!< Data bit is active high for self test mode */ -#define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */ -#else -//Test with infrared LED, we have to enable carrier for transmitter -//When testing via IR led, the receiver waveform is usually active-low. -#define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */ -#define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */ -#endif - -#define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */ -#define RMT_TX_GPIO_NUM 16 /*!< GPIO number for transmitter signal */ -#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */ -#define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */ -#define RMT_CLK_DIV 100 /*!< RMT counter clock divider */ -#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */ - -#define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */ -#define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/ -#define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */ -#define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */ -#define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */ -#define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */ -#define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */ -#define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */ - -#define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */ -#define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */ -#define RMT_TX_DATA_NUM 100 /*!< NEC tx test data number */ -#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */ - -/* - * @brief Build register value of waveform for NEC one data bit - */ -inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us) -{ - item->level0 = 1; - item->duration0 = (high_us) / 10 * RMT_TICK_10_US; - item->level1 = 0; - item->duration1 = (low_us) / 10 * RMT_TICK_10_US; -} - -/* - * @brief Generate NEC header value: active 9ms + negative 4.5ms - */ -static void nec_fill_item_header(rmt_item32_t* item) -{ - nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US); -} - -/* - * @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms - */ -static void nec_fill_item_bit_one(rmt_item32_t* item) -{ - nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US); -} - -/* - * @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms - */ -static void nec_fill_item_bit_zero(rmt_item32_t* item) -{ - nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US); -} - -/* - * @brief Generate NEC end signal: positive 0.56ms - */ -static void nec_fill_item_end(rmt_item32_t* item) -{ - nec_fill_item_level(item, NEC_BIT_END, 0x7fff); -} - -/* - * @brief Check whether duration is around target_us - */ -inline bool nec_check_in_range(int duration_ticks, int target_us, int margin_us) -{ - if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us)) - && ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) { - return true; - } else { - return false; - } -} - -/* - * @brief Check whether this value represents an NEC header - */ -static bool nec_header_if(rmt_item32_t* item) -{ - if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) - && nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN) - && nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) { - return true; - } - return false; -} - -/* - * @brief Check whether this value represents an NEC data bit 1 - */ -static bool nec_bit_one_if(rmt_item32_t* item) -{ - if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) - && nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN) - && nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) { - return true; - } - return false; -} - -/* - * @brief Check whether this value represents an NEC data bit 0 - */ -static bool nec_bit_zero_if(rmt_item32_t* item) -{ - if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) - && nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN) - && nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) { - return true; - } - return false; -} - - -/* - * @brief Parse NEC 32 bit waveform to address and command. - */ -static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data) -{ - int w_len = item_num; - if(w_len < NEC_DATA_ITEM_NUM) { - return -1; - } - int i = 0, j = 0; - if(!nec_header_if(item++)) { - return -1; - } - uint16_t addr_t = 0; - for(j = 0; j < 16; j++) { - if(nec_bit_one_if(item)) { - addr_t |= (1 << j); - } else if(nec_bit_zero_if(item)) { - addr_t |= (0 << j); - } else { - return -1; - } - item++; - i++; - } - uint16_t data_t = 0; - for(j = 0; j < 16; j++) { - if(nec_bit_one_if(item)) { - data_t |= (1 << j); - } else if(nec_bit_zero_if(item)) { - data_t |= (0 << j); - } else { - return -1; - } - item++; - i++; - } - *addr = addr_t; - *data = data_t; - return i; -} - -/* - * @brief Build NEC 32bit waveform. - */ -static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data) -{ - int i = 0, j = 0; - if(item_num < NEC_DATA_ITEM_NUM) { - return -1; - } - nec_fill_item_header(item++); - i++; - for(j = 0; j < 16; j++) { - if(addr & 0x1) { - nec_fill_item_bit_one(item); - } else { - nec_fill_item_bit_zero(item); - } - item++; - i++; - addr >>= 1; - } - for(j = 0; j < 16; j++) { - if(cmd_data & 0x1) { - nec_fill_item_bit_one(item); - } else { - nec_fill_item_bit_zero(item); - } - item++; - i++; - cmd_data >>= 1; - } - nec_fill_item_end(item); - i++; - return i; -} - -/* - * @brief RMT transmitter initialization - */ -static void rmt_tx_init() -{ - rmt_config_t rmt_tx; - rmt_tx.channel = RMT_TX_CHANNEL; - rmt_tx.gpio_num = RMT_TX_GPIO_NUM; - rmt_tx.mem_block_num = 1; - rmt_tx.clk_div = RMT_CLK_DIV; - 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); - rmt_driver_install(rmt_tx.channel, 0, 0); -} - -/* - * @brief RMT receiver initialization - */ -void rmt_rx_init() -{ - rmt_config_t rmt_rx; - rmt_rx.channel = RMT_RX_CHANNEL; - rmt_rx.gpio_num = RMT_RX_GPIO_NUM; - rmt_rx.clk_div = RMT_CLK_DIV; - 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 = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US); - rmt_config(&rmt_rx); - rmt_driver_install(rmt_rx.channel, 1000, 0); -} - -/** - * @brief RMT receiver demo, this task will print each received NEC data. - * - */ -void rmt_nec_rx_task() -{ - int channel = RMT_RX_CHANNEL; - rmt_rx_init(); - RingbufHandle_t rb = NULL; - //get RMT RX ringbuffer - rmt_get_ringbuf_handler(channel, &rb); - rmt_rx_start(channel, 1); - while(rb) { - size_t rx_size = 0; - //try to receive data from ringbuffer. - //RMT driver will push all the data it receives to its ringbuffer. - //We just need to parse the value and return the spaces of ringbuffer. - rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000); - if(item) { - uint16_t rmt_addr; - uint16_t rmt_cmd; - int offset = 0; - while(1) { - //parse data value from ringbuffer. - int res = nec_parse_items(item + offset, rx_size / 4 - offset, &rmt_addr, &rmt_cmd); - if(res > 0) { - offset += res + 1; - ESP_LOGI(NEC_TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", rmt_addr, rmt_cmd); - } else { - break; - } - } - //after parsing the data, return spaces to ringbuffer. - vRingbufferReturnItem(rb, (void*) item); - } else { - break; - } - } - vTaskDelete(NULL); -} - -/** - * @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.) - * - */ -void rmt_nec_tx_task() -{ - vTaskDelay(10); - rmt_tx_init(); - esp_log_level_set(NEC_TAG, ESP_LOG_INFO); - int channel = RMT_TX_CHANNEL; - uint16_t cmd = 0x0; - uint16_t addr = 0x11; - int nec_tx_num = RMT_TX_DATA_NUM; - for(;;) { - ESP_LOGI(NEC_TAG, "RMT TX DATA"); - size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num); - //each item represent a cycle of waveform. - rmt_item32_t* item = (rmt_item32_t*) malloc(size); - int item_num = NEC_DATA_ITEM_NUM * nec_tx_num; - memset((void*) item, 0, size); - int i, offset = 0; - while(1) { - //To build a series of waveforms. - i = nec_build_items(channel, item + offset, item_num - offset, ((~addr) << 8) | addr, cmd); - if(i < 0) { - break; - } - cmd++; - addr++; - offset += i; - } - //To send data according to the waveform items. - rmt_write_items(channel, item, item_num, true); - //Wait until sending is done. - rmt_wait_tx_done(channel); - //before we free the data, make sure sending is already done. - free(item); - vTaskDelay(2000 / portTICK_PERIOD_MS); - } - vTaskDelete(NULL); -} diff --git a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c index c680f25a5..1bc01a386 100644 --- a/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c +++ b/examples/peripherals/rmt_nec_tx_rx/main/infrared_nec_main.c @@ -7,17 +7,358 @@ CONDITIONS OF ANY KIND, either express or implied. */ #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_system.h" -#include "nvs_flash.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "esp_err.h" +#include "esp_log.h" #include "driver/rmt.h" #include "driver/periph_ctrl.h" -extern void rmt_nec_tx_task(); -extern void rmt_nec_rx_task(); +#include "soc/rmt_reg.h" + +static const char* NEC_TAG = "NEC"; + +//CHOOSE SELF TEST OR NORMAL TEST +#define RMT_RX_SELF_TEST 1 + +/******************************************************/ +/***** SELF TEST: *****/ +/*Connect RMT_TX_GPIO_NUM with RMT_RX_GPIO_NUM */ +/*TX task will send NEC data with carrier disabled */ +/*RX task will print NEC data it receives. */ +/******************************************************/ +#if RMT_RX_SELF_TEST +#define RMT_RX_ACTIVE_LEVEL 1 /*!< Data bit is active high for self test mode */ +#define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */ +#else +//Test with infrared LED, we have to enable carrier for transmitter +//When testing via IR led, the receiver waveform is usually active-low. +#define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */ +#define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */ +#endif + +#define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */ +#define RMT_TX_GPIO_NUM 16 /*!< GPIO number for transmitter signal */ +#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */ +#define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */ +#define RMT_CLK_DIV 100 /*!< RMT counter clock divider */ +#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */ + +#define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */ +#define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/ +#define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */ +#define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */ +#define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */ +#define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */ +#define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */ +#define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */ + +#define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */ +#define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */ +#define RMT_TX_DATA_NUM 100 /*!< NEC tx test data number */ +#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */ + +/* + * @brief Build register value of waveform for NEC one data bit + */ +static inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us) +{ + item->level0 = 1; + item->duration0 = (high_us) / 10 * RMT_TICK_10_US; + item->level1 = 0; + item->duration1 = (low_us) / 10 * RMT_TICK_10_US; +} + +/* + * @brief Generate NEC header value: active 9ms + negative 4.5ms + */ +static void nec_fill_item_header(rmt_item32_t* item) +{ + nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US); +} + +/* + * @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms + */ +static void nec_fill_item_bit_one(rmt_item32_t* item) +{ + nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US); +} + +/* + * @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms + */ +static void nec_fill_item_bit_zero(rmt_item32_t* item) +{ + nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US); +} + +/* + * @brief Generate NEC end signal: positive 0.56ms + */ +static void nec_fill_item_end(rmt_item32_t* item) +{ + nec_fill_item_level(item, NEC_BIT_END, 0x7fff); +} + +/* + * @brief Check whether duration is around target_us + */ +inline bool nec_check_in_range(int duration_ticks, int target_us, int margin_us) +{ + if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us)) + && ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) { + return true; + } else { + return false; + } +} + +/* + * @brief Check whether this value represents an NEC header + */ +static bool nec_header_if(rmt_item32_t* item) +{ + if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) + && nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN) + && nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) { + return true; + } + return false; +} + +/* + * @brief Check whether this value represents an NEC data bit 1 + */ +static bool nec_bit_one_if(rmt_item32_t* item) +{ + if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) + && nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN) + && nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) { + return true; + } + return false; +} + +/* + * @brief Check whether this value represents an NEC data bit 0 + */ +static bool nec_bit_zero_if(rmt_item32_t* item) +{ + if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL) + && nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN) + && nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) { + return true; + } + return false; +} + + +/* + * @brief Parse NEC 32 bit waveform to address and command. + */ +static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data) +{ + int w_len = item_num; + if(w_len < NEC_DATA_ITEM_NUM) { + return -1; + } + int i = 0, j = 0; + if(!nec_header_if(item++)) { + return -1; + } + uint16_t addr_t = 0; + for(j = 0; j < 16; j++) { + if(nec_bit_one_if(item)) { + addr_t |= (1 << j); + } else if(nec_bit_zero_if(item)) { + addr_t |= (0 << j); + } else { + return -1; + } + item++; + i++; + } + uint16_t data_t = 0; + for(j = 0; j < 16; j++) { + if(nec_bit_one_if(item)) { + data_t |= (1 << j); + } else if(nec_bit_zero_if(item)) { + data_t |= (0 << j); + } else { + return -1; + } + item++; + i++; + } + *addr = addr_t; + *data = data_t; + return i; +} + +/* + * @brief Build NEC 32bit waveform. + */ +static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data) +{ + int i = 0, j = 0; + if(item_num < NEC_DATA_ITEM_NUM) { + return -1; + } + nec_fill_item_header(item++); + i++; + for(j = 0; j < 16; j++) { + if(addr & 0x1) { + nec_fill_item_bit_one(item); + } else { + nec_fill_item_bit_zero(item); + } + item++; + i++; + addr >>= 1; + } + for(j = 0; j < 16; j++) { + if(cmd_data & 0x1) { + nec_fill_item_bit_one(item); + } else { + nec_fill_item_bit_zero(item); + } + item++; + i++; + cmd_data >>= 1; + } + nec_fill_item_end(item); + i++; + return i; +} + +/* + * @brief RMT transmitter initialization + */ +static void nec_tx_init() +{ + rmt_config_t rmt_tx; + rmt_tx.channel = RMT_TX_CHANNEL; + rmt_tx.gpio_num = RMT_TX_GPIO_NUM; + rmt_tx.mem_block_num = 1; + rmt_tx.clk_div = RMT_CLK_DIV; + 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); + rmt_driver_install(rmt_tx.channel, 0, 0); +} + +/* + * @brief RMT receiver initialization + */ +static void nec_rx_init() +{ + rmt_config_t rmt_rx; + rmt_rx.channel = RMT_RX_CHANNEL; + rmt_rx.gpio_num = RMT_RX_GPIO_NUM; + rmt_rx.clk_div = RMT_CLK_DIV; + 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 = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US); + rmt_config(&rmt_rx); + rmt_driver_install(rmt_rx.channel, 1000, 0); +} + +/** + * @brief RMT receiver demo, this task will print each received NEC data. + * + */ +static void rmt_example_nec_rx_task() +{ + int channel = RMT_RX_CHANNEL; + nec_rx_init(); + RingbufHandle_t rb = NULL; + //get RMT RX ringbuffer + rmt_get_ringbuf_handler(channel, &rb); + rmt_rx_start(channel, 1); + while(rb) { + size_t rx_size = 0; + //try to receive data from ringbuffer. + //RMT driver will push all the data it receives to its ringbuffer. + //We just need to parse the value and return the spaces of ringbuffer. + rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000); + if(item) { + uint16_t rmt_addr; + uint16_t rmt_cmd; + int offset = 0; + while(1) { + //parse data value from ringbuffer. + int res = nec_parse_items(item + offset, rx_size / 4 - offset, &rmt_addr, &rmt_cmd); + if(res > 0) { + offset += res + 1; + ESP_LOGI(NEC_TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", rmt_addr, rmt_cmd); + } else { + break; + } + } + //after parsing the data, return spaces to ringbuffer. + vRingbufferReturnItem(rb, (void*) item); + } else { + break; + } + } + vTaskDelete(NULL); +} + +/** + * @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.) + * + */ +static void rmt_example_nec_tx_task() +{ + vTaskDelay(10); + nec_tx_init(); + esp_log_level_set(NEC_TAG, ESP_LOG_INFO); + int channel = RMT_TX_CHANNEL; + uint16_t cmd = 0x0; + uint16_t addr = 0x11; + int nec_tx_num = RMT_TX_DATA_NUM; + for(;;) { + ESP_LOGI(NEC_TAG, "RMT TX DATA"); + size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num); + //each item represent a cycle of waveform. + rmt_item32_t* item = (rmt_item32_t*) malloc(size); + int item_num = NEC_DATA_ITEM_NUM * nec_tx_num; + memset((void*) item, 0, size); + int i, offset = 0; + while(1) { + //To build a series of waveforms. + i = nec_build_items(channel, item + offset, item_num - offset, ((~addr) << 8) | addr, cmd); + if(i < 0) { + break; + } + cmd++; + addr++; + offset += i; + } + //To send data according to the waveform items. + rmt_write_items(channel, item, item_num, true); + //Wait until sending is done. + rmt_wait_tx_done(channel); + //before we free the data, make sure sending is already done. + free(item); + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} void app_main() { - xTaskCreate(rmt_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL); - xTaskCreate(rmt_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL); + xTaskCreate(rmt_example_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL); + xTaskCreate(rmt_example_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL); } diff --git a/examples/peripherals/sigmadelta/main/sigmadelta_test.c b/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c similarity index 95% rename from examples/peripherals/sigmadelta/main/sigmadelta_test.c rename to examples/peripherals/sigmadelta/main/sigmadelta_example_main.c index 60880311d..5249d2dea 100644 --- a/examples/peripherals/sigmadelta/main/sigmadelta_test.c +++ b/examples/peripherals/sigmadelta/main/sigmadelta_example_main.c @@ -20,7 +20,7 @@ /** * @brief Sigma-delta initialization. */ -static void sigmadelta_init(void) +static void sigmadelta_example_init(void) { sigmadelta_config_t sigmadelta_cfg = { /* Sigma-delta channel0*/ @@ -40,7 +40,7 @@ static void sigmadelta_init(void) */ void app_main() { - sigmadelta_init(); + sigmadelta_example_init(); int8_t duty = 0; int inc = 1; while(1) { diff --git a/examples/peripherals/spi_master/main/spi_master.c b/examples/peripherals/spi_master/main/spi_master_example_main.c similarity index 98% rename from examples/peripherals/spi_master/main/spi_master.c rename to examples/peripherals/spi_master/main/spi_master_example_main.c index 577cada4c..b9cdd2009 100644 --- a/examples/peripherals/spi_master/main/spi_master.c +++ b/examples/peripherals/spi_master/main/spi_master_example_main.c @@ -147,7 +147,7 @@ void ili_init(spi_device_handle_t spi) //before sending the line data itself; a total of 6 transactions. (We can't put all of this in just one transaction //because the D/C line needs to be toggled in the middle.) //This routine queues these commands up so they get sent as quickly as possible. -void send_line(spi_device_handle_t spi, int ypos, uint16_t *line) +static void send_line(spi_device_handle_t spi, int ypos, uint16_t *line) { esp_err_t ret; int x; @@ -198,7 +198,7 @@ void send_line(spi_device_handle_t spi, int ypos, uint16_t *line) } -void send_line_finish(spi_device_handle_t spi) +static void send_line_finish(spi_device_handle_t spi) { spi_transaction_t *rtrans; esp_err_t ret; @@ -214,7 +214,7 @@ void send_line_finish(spi_device_handle_t spi) //Simple routine to generate some patterns and send them to the LCD. Don't expect anything too //impressive. Because the SPI driver handles transactions in the background, we can calculate the next line //while the previous one is being sent. -void display_pretty_colors(spi_device_handle_t spi) +static void display_pretty_colors(spi_device_handle_t spi) { uint16_t line[2][320]; int x, y, frame=0; diff --git a/examples/peripherals/timer_group/main/timer_group.c b/examples/peripherals/timer_group/main/timer_group_example_main.c similarity index 96% rename from examples/peripherals/timer_group/main/timer_group.c rename to examples/peripherals/timer_group/main/timer_group_example_main.c index 37e22faaf..fcc25dcf0 100644 --- a/examples/peripherals/timer_group/main/timer_group.c +++ b/examples/peripherals/timer_group/main/timer_group_example_main.c @@ -44,7 +44,7 @@ static void inline print_u64(uint64_t val) printf("0x%08x%08x\n", (uint32_t) (val >> 32), (uint32_t) (val)); } -void timer_evt_task(void *arg) +static void timer_example_evt_task(void *arg) { while(1) { timer_event_t evt; @@ -135,7 +135,7 @@ void IRAM_ATTR timer_group0_isr(void *para) /* * @brief timer group0 hardware timer0 init */ -void tg0_timer0_init() +static void example_tg0_timer0_init() { int timer_group = TIMER_GROUP_0; int timer_idx = TIMER_0; @@ -165,7 +165,7 @@ void tg0_timer0_init() /* * @brief timer group0 hardware timer1 init */ -void tg0_timer1_init() +static void example_tg0_timer1_init() { int timer_group = TIMER_GROUP_0; int timer_idx = TIMER_1; @@ -198,8 +198,8 @@ void tg0_timer1_init() void app_main() { timer_queue = xQueueCreate(10, sizeof(timer_event_t)); - tg0_timer0_init(); - tg0_timer1_init(); - xTaskCreate(timer_evt_task, "timer_evt_task", 2048, NULL, 5, NULL); + example_tg0_timer0_init(); + example_tg0_timer1_init(); + xTaskCreate(timer_example_evt_task, "timer_evt_task", 2048, NULL, 5, NULL); } diff --git a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c index 90f94f65f..490d8683e 100644 --- a/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c +++ b/examples/peripherals/touch_pad_interrupt/main/tp_interrupt_main.c @@ -17,7 +17,7 @@ static const char* TAG = "Touch pad"; -static bool touch_pad_activated[TOUCH_PAD_MAX]; +static bool s_pad_activated[TOUCH_PAD_MAX]; /* @@ -29,7 +29,7 @@ static bool touch_pad_activated[TOUCH_PAD_MAX]; Do not touch any pads when this routine is running (on application start). */ -static void touch_pad_set_thresholds(void) +static void tp_example_set_thresholds(void) { uint16_t touch_value; for (int i=0; i> i) & 0x01) { - touch_pad_activated[i] = true; + s_pad_activated[i] = true; } } } @@ -96,9 +96,9 @@ void app_main() // Initialize touch pad peripheral ESP_LOGI(TAG, "Initializing touch pad"); touch_pad_init(); - touch_pad_set_thresholds(); - touch_pad_isr_handler_register(touch_pad_rtc_intr, NULL, 0, NULL); + tp_example_set_thresholds(); + touch_pad_isr_handler_register(tp_example_rtc_intr, NULL, 0, NULL); // Start a task to show what pads have been touched - xTaskCreate(&touch_pad_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); + xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); } diff --git a/examples/peripherals/touch_pad_read/main/tp_read_main.c b/examples/peripherals/touch_pad_read/main/tp_read_main.c index 69bb87d17..da7baa6ba 100644 --- a/examples/peripherals/touch_pad_read/main/tp_read_main.c +++ b/examples/peripherals/touch_pad_read/main/tp_read_main.c @@ -17,7 +17,7 @@ Read values sensed at all available touch pads. Print out values in a loop on a serial monitor. */ -void touch_pad_read_task(void *pvParameter) +static void tp_example_read_task(void *pvParameter) { while (1) { uint16_t touch_value; @@ -36,6 +36,6 @@ void app_main() touch_pad_init(); // Start task to read values sensed by pads - xTaskCreate(&touch_pad_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); + xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL); } diff --git a/examples/peripherals/uart/Makefile b/examples/peripherals/uart_echo/Makefile similarity index 85% rename from examples/peripherals/uart/Makefile rename to examples/peripherals/uart_echo/Makefile index 4c523bd68..e4714e57f 100644 --- a/examples/peripherals/uart/Makefile +++ b/examples/peripherals/uart_echo/Makefile @@ -3,7 +3,7 @@ # project subdirectory. # -PROJECT_NAME := uart +PROJECT_NAME := uart_echo include $(IDF_PATH)/make/project.mk diff --git a/examples/peripherals/uart/main/component.mk b/examples/peripherals/uart_echo/main/component.mk similarity index 100% rename from examples/peripherals/uart/main/component.mk rename to examples/peripherals/uart_echo/main/component.mk diff --git a/examples/peripherals/uart_echo/main/uart_echo_example_main.c b/examples/peripherals/uart_echo/main/uart_echo_example_main.c new file mode 100644 index 000000000..5b8baf7fb --- /dev/null +++ b/examples/peripherals/uart_echo/main/uart_echo_example_main.c @@ -0,0 +1,73 @@ +/* Uart Events 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 +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "driver/uart.h" +#include "freertos/queue.h" +#include "esp_log.h" +#include "soc/uart_struct.h" + +/** + * This is a example exaple which echos any data it receives on UART1 back to the sender, with hardware flow control + * turned on. It does not use UART driver event queue. + * + * - port: UART1 + * - rx buffer: on + * - tx buffer: off + * - flow control: on + * - event queue: off + * - pin assignment: txd(io4), rxd(io5), rts(18), cts(19) + */ + +#define ECHO_TEST_TXD (4) +#define ECHO_TEST_RXD (5) +#define ECHO_TEST_RTS (18) +#define ECHO_TEST_CTS (19) + +#define BUF_SIZE (1024) + +//an example of echo test with hardware flow control on UART1 +static void echo_task() +{ + const int uart_num = UART_NUM_1; + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, + .rx_flow_ctrl_thresh = 122, + }; + //Configure UART1 parameters + uart_param_config(uart_num, &uart_config); + //Set UART1 pins(TX: IO4, RX: I05, RTS: IO18, CTS: IO19) + uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); + //Install UART driver (we don't need an event queue here) + //In this example we don't even use a buffer for sending data. + uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); + + uint8_t* data = (uint8_t*) malloc(BUF_SIZE); + while(1) { + //Read data from UART + int len = uart_read_bytes(uart_num, data, BUF_SIZE, 20 / portTICK_RATE_MS); + //Write data back to UART + uart_write_bytes(uart_num, (const char*) data, len); + } +} + +void app_main() +{ + //A uart read/write example without event queue; + xTaskCreate(echo_task, "uart_echo_task", 1024, NULL, 10, NULL); +} diff --git a/examples/peripherals/uart_events/Makefile b/examples/peripherals/uart_events/Makefile new file mode 100644 index 000000000..496941720 --- /dev/null +++ b/examples/peripherals/uart_events/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := uart_events + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/peripherals/uart_events/main/component.mk b/examples/peripherals/uart_events/main/component.mk new file mode 100644 index 000000000..44bd2b527 --- /dev/null +++ b/examples/peripherals/uart_events/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/examples/peripherals/uart/main/uart_test.c b/examples/peripherals/uart_events/main/uart_events_example_main.c similarity index 57% rename from examples/peripherals/uart/main/uart_test.c rename to examples/peripherals/uart_events/main/uart_events_example_main.c index 9a0d0003c..50cbad7e5 100644 --- a/examples/peripherals/uart/main/uart_test.c +++ b/examples/peripherals/uart_events/main/uart_events_example_main.c @@ -17,46 +17,36 @@ #include "freertos/queue.h" #include "esp_log.h" #include "soc/uart_struct.h" -static const char *TAG = "uart_example"; + +static const char *TAG = "uart_events"; /** - * Test code brief - * This example shows how to configure uart settings and install uart driver. + * This example shows how to use the UART driver to handle special UART events. + * + * It also reads data from UART0 directly, and echoes it to console. * - * uart_evt_test() is an example that read and write data on UART0, and handler some of the special events. * - port: UART0 * - rx buffer: on * - tx buffer: on * - flow control: off * - event queue: on * - pin assignment: txd(default), rxd(default) - * - * uart_echo_test() is an example that read and write data on UART1, with hardware flow control turning on. - * - port: UART1 - * - rx buffer: on - * - tx buffer: off - * - flow control: on - * - event queue: off - * - pin assignment: txd(io4), rxd(io5), rts(18), cts(19) */ -#define BUF_SIZE (1024) -#define ECHO_TEST_TXD (4) -#define ECHO_TEST_RXD (5) -#define ECHO_TEST_RTS (18) -#define ECHO_TEST_CTS (19) +#define EX_UART_NUM UART_NUM_0 -QueueHandle_t uart0_queue; -void uart_task(void *pvParameters) +#define BUF_SIZE (1024) +static QueueHandle_t uart0_queue; + +static void uart_event_task(void *pvParameters) { - int uart_num = (int) pvParameters; uart_event_t event; size_t buffered_size; uint8_t* dtmp = (uint8_t*) malloc(BUF_SIZE); for(;;) { //Waiting for UART event. if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { - ESP_LOGI(TAG, "uart[%d] event:", uart_num); + ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM); switch(event.type) { //Event of UART receving data /*We'd better handler data event fast, there would be much more data events than @@ -64,7 +54,7 @@ void uart_task(void *pvParameters) be full. in this example, we don't process data in event, but read data outside.*/ case UART_DATA: - uart_get_buffered_data_len(uart_num, &buffered_size); + uart_get_buffered_data_len(EX_UART_NUM, &buffered_size); ESP_LOGI(TAG, "data, len: %d; buffered len: %d", event.size, buffered_size); break; //Event of HW FIFO overflow detected @@ -72,14 +62,14 @@ void uart_task(void *pvParameters) ESP_LOGI(TAG, "hw fifo overflow\n"); //If fifo overflow happened, you should consider adding flow control for your application. //We can read data out out the buffer, or directly flush the rx buffer. - uart_flush(uart_num); + uart_flush(EX_UART_NUM); break; //Event of UART ring buffer full case UART_BUFFER_FULL: ESP_LOGI(TAG, "ring buffer full\n"); //If buffer full happened, you should consider encreasing your buffer size //We can read data out out the buffer, or directly flush the rx buffer. - uart_flush(uart_num); + uart_flush(EX_UART_NUM); break; //Event of UART RX break detected case UART_BREAK: @@ -109,9 +99,9 @@ void uart_task(void *pvParameters) vTaskDelete(NULL); } -void uart_evt_test() +/* Configure the UART events example */ +void app_main() { - int uart_num = UART_NUM_0; uart_config_t uart_config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, @@ -121,63 +111,26 @@ void uart_evt_test() .rx_flow_ctrl_thresh = 122, }; //Set UART parameters - uart_param_config(uart_num, &uart_config); + uart_param_config(EX_UART_NUM, &uart_config); //Set UART log level esp_log_level_set(TAG, ESP_LOG_INFO); //Install UART driver, and get the queue. - uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0); - //Set UART pins,(-1: default pin, no change.) - //For UART0, we can just use the default pins. - //uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0); + + //Set UART pins (using UART0 default pins ie no changes.) + uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + //Set uart pattern detect function. - uart_enable_pattern_det_intr(uart_num, '+', 3, 10000, 10, 10); + uart_enable_pattern_det_intr(EX_UART_NUM, '+', 3, 10000, 10, 10); //Create a task to handler UART event from ISR - xTaskCreate(uart_task, "uart_task", 2048, (void*)uart_num, 12, NULL); + xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL); //process data uint8_t* data = (uint8_t*) malloc(BUF_SIZE); do { - int len = uart_read_bytes(uart_num, data, BUF_SIZE, 100 / portTICK_RATE_MS); + int len = uart_read_bytes(EX_UART_NUM, data, BUF_SIZE, 100 / portTICK_RATE_MS); if(len > 0) { ESP_LOGI(TAG, "uart read : %d", len); - uart_write_bytes(uart_num, (const char*)data, len); + uart_write_bytes(EX_UART_NUM, (const char*)data, len); } } while(1); } - -//an example of echo test with hardware flow control on UART1 -void uart_echo_test() -{ - int uart_num = UART_NUM_1; - uart_config_t uart_config = { - .baud_rate = 115200, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, - .rx_flow_ctrl_thresh = 122, - }; - //Configure UART1 parameters - uart_param_config(uart_num, &uart_config); - //Set UART1 pins(TX: IO4, RX: I05, RTS: IO18, CTS: IO19) - uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); - //Install UART driver( We don't need an event queue here) - //In this example we don't even use a buffer for sending data. - uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); - - uint8_t* data = (uint8_t*) malloc(BUF_SIZE); - while(1) { - //Read data from UART - int len = uart_read_bytes(uart_num, data, BUF_SIZE, 20 / portTICK_RATE_MS); - //Write data back to UART - uart_write_bytes(uart_num, (const char*) data, len); - } -} - -void app_main() -{ - //A uart read/write example without event queue; - xTaskCreate(uart_echo_test, "uart_echo_test", 1024, NULL, 10, NULL); - - //A uart example with event queue. - uart_evt_test(); -} diff --git a/examples/protocols/coap_client/main/coap_client.c b/examples/protocols/coap_client/main/coap_client_example_main.c similarity index 98% rename from examples/protocols/coap_client/main/coap_client.c rename to examples/protocols/coap_client/main/coap_client_example_main.c index a45f748d4..c9d8b22fc 100644 --- a/examples/protocols/coap_client/main/coap_client.c +++ b/examples/protocols/coap_client/main/coap_client_example_main.c @@ -65,7 +65,7 @@ static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *l } } -static void coap_demo_thread(void *p) +static void coap_example_task(void *p) { struct hostent *hp; struct ip4_addr *ip4_addr; @@ -201,5 +201,5 @@ void app_main(void) { ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); - xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); + xTaskCreate(coap_example_task, "coap", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/coap_server/main/coap_server.c b/examples/protocols/coap_server/main/coap_server_example_main.c similarity index 98% rename from examples/protocols/coap_server/main/coap_server.c rename to examples/protocols/coap_server/main/coap_server_example_main.c index f23285388..47f47dfc5 100644 --- a/examples/protocols/coap_server/main/coap_server.c +++ b/examples/protocols/coap_server/main/coap_server_example_main.c @@ -80,7 +80,7 @@ async_handler(coap_context_t *ctx, struct coap_resource_t *resource, async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data"); } -static void coap_demo_thread(void *p) +static void coap_example_thread(void *p) { coap_context_t* ctx = NULL; coap_address_t serv_addr; @@ -188,5 +188,5 @@ void app_main(void) ESP_ERROR_CHECK( nvs_flash_init() ); wifi_conn_init(); - xTaskCreate(coap_demo_thread, "coap", 2048, NULL, 5, NULL); + xTaskCreate(coap_example_thread, "coap", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/http_request/main/http_request_main.c b/examples/protocols/http_request/main/http_request_example_main.c similarity index 100% rename from examples/protocols/http_request/main/http_request_main.c rename to examples/protocols/http_request/main/http_request_example_main.c diff --git a/examples/protocols/https_request/main/https_request_main.c b/examples/protocols/https_request/main/https_request_example_main.c similarity index 100% rename from examples/protocols/https_request/main/https_request_main.c rename to examples/protocols/https_request/main/https_request_example_main.c diff --git a/examples/protocols/mdns/main/mdns_example_main.c b/examples/protocols/mdns/main/mdns_example_main.c index 50b74e08c..29e4e9b47 100644 --- a/examples/protocols/mdns/main/mdns_example_main.c +++ b/examples/protocols/mdns/main/mdns_example_main.c @@ -125,7 +125,7 @@ static void query_mdns_service(mdns_server_t * mdns, const char * service, const } } -static void mdns_task(void *pvParameters) +static void mdns_example_task(void *pvParameters) { mdns_server_t * mdns = NULL; while(1) { @@ -180,5 +180,5 @@ void app_main() { ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); - xTaskCreate(&mdns_task, "mdns_task", 2048, NULL, 5, NULL); + xTaskCreate(&mdns_example_task, "mdns_example_task", 2048, NULL, 5, NULL); } diff --git a/examples/protocols/openssl_client/main/openssl_client.h b/examples/protocols/openssl_client/main/openssl_client_example.h similarity index 56% rename from examples/protocols/openssl_client/main/openssl_client.h rename to examples/protocols/openssl_client/main/openssl_client_example.h index f5ab887ad..7b6ef8d40 100644 --- a/examples/protocols/openssl_client/main/openssl_client.h +++ b/examples/protocols/openssl_client/main/openssl_client_example.h @@ -7,8 +7,8 @@ CONDITIONS OF ANY KIND, either express or implied. */ -#ifndef _OPENSSL_DEMO_H_ -#define _OPENSSL_DEMO_H_ +#ifndef _OPENSSL_EXAMPLE_H_ +#define _OPENSSL_EXAMPLE_H_ /* The examples use simple WiFi configuration that you can set via 'make menuconfig'. @@ -23,21 +23,21 @@ you can set via 'make menuconfig'. If you'd rather not, just change the below entries to strings with - the config you want - ie #define OPENSSL_DEMO_TARGET_NAME "www.baidu.com" - and ie #define OPENSSL_DEMO_TARGET_TCP_PORT 433 + the config you want - ie #define OPENSSL_EXAMPLE_TARGET_NAME "www.baidu.com" + and ie #define OPENSSL_EXAMPLE_TARGET_TCP_PORT 433 */ -#define OPENSSL_DEMO_TARGET_NAME CONFIG_TARGET_DOMAIN -#define OPENSSL_DEMO_TARGET_TCP_PORT CONFIG_TARGET_PORT_NUMBER +#define OPENSSL_EXAMPLE_TARGET_NAME CONFIG_TARGET_DOMAIN +#define OPENSSL_EXAMPLE_TARGET_TCP_PORT CONFIG_TARGET_PORT_NUMBER -#define OPENSSL_DEMO_REQUEST "{\"path\": \"/v1/ping/\", \"method\": \"GET\"}\r\n" +#define OPENSSL_EXAMPLE_REQUEST "{\"path\": \"/v1/ping/\", \"method\": \"GET\"}\r\n" -#define OPENSSL_DEMO_THREAD_NAME "OpenSSL_demo" -#define OPENSSL_DEMO_THREAD_STACK_WORDS 10240 -#define OPENSSL_DEMO_THREAD_PRORIOTY 8 +#define OPENSSL_EXAMPLE_TASK_NAME "openssl_example" +#define OPENSSL_EXAMPLE_TASK_STACK_WORDS 10240 +#define OPENSSL_EXAMPLE_TASK_PRORIOTY 8 -#define OPENSSL_DEMO_RECV_BUF_LEN 1024 +#define OPENSSL_EXAMPLE_RECV_BUF_LEN 1024 -#define OPENSSL_DEMO_LOCAL_TCP_PORT 443 +#define OPENSSL_EXAMPLE_LOCAL_TCP_PORT 443 #endif diff --git a/examples/protocols/openssl_client/main/openssl_client.c b/examples/protocols/openssl_client/main/openssl_client_example_main.c similarity index 82% rename from examples/protocols/openssl_client/main/openssl_client.c rename to examples/protocols/openssl_client/main/openssl_client_example_main.c index 16c9a0efa..cb114ddf8 100644 --- a/examples/protocols/openssl_client/main/openssl_client.c +++ b/examples/protocols/openssl_client/main/openssl_client_example_main.c @@ -7,7 +7,7 @@ CONDITIONS OF ANY KIND, either express or implied. */ -#include "openssl_client.h" +#include "openssl_client_example.h" #include @@ -33,9 +33,9 @@ static EventGroupHandle_t wifi_event_group; to the AP with an IP? */ const static int CONNECTED_BIT = BIT0; -const static char *TAG = "Openssl_demo"; +const static char *TAG = "openssl_example"; -void openssl_demo_thread(void *p) +static void openssl_example_task(void *p) { int ret; SSL_CTX *ctx; @@ -46,15 +46,15 @@ void openssl_demo_thread(void *p) struct ip4_addr *ip4_addr; int recv_bytes = 0; - char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + char recv_buf[OPENSSL_EXAMPLE_RECV_BUF_LEN]; - const char send_data[] = OPENSSL_DEMO_REQUEST; + const char send_data[] = OPENSSL_EXAMPLE_REQUEST; const int send_bytes = sizeof(send_data); ESP_LOGI(TAG, "OpenSSL demo thread start OK"); ESP_LOGI(TAG, "get target IP address"); - hp = gethostbyname(OPENSSL_DEMO_TARGET_NAME); + hp = gethostbyname(OPENSSL_EXAMPLE_TARGET_NAME); if (!hp) { ESP_LOGI(TAG, "failed"); goto failed1; @@ -84,7 +84,7 @@ void openssl_demo_thread(void *p) memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = 0; - sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + sock_addr.sin_port = htons(OPENSSL_EXAMPLE_LOCAL_TCP_PORT); ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); if (ret) { ESP_LOGI(TAG, "failed"); @@ -92,11 +92,11 @@ void openssl_demo_thread(void *p) } ESP_LOGI(TAG, "OK"); - ESP_LOGI(TAG, "socket connect to remote %s ......", OPENSSL_DEMO_TARGET_NAME); + ESP_LOGI(TAG, "socket connect to remote %s ......", OPENSSL_EXAMPLE_TARGET_NAME); memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = ip4_addr->addr; - sock_addr.sin_port = htons(OPENSSL_DEMO_TARGET_TCP_PORT); + sock_addr.sin_port = htons(OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = connect(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); if (ret) { ESP_LOGI(TAG, "failed"); @@ -115,7 +115,7 @@ void openssl_demo_thread(void *p) SSL_set_fd(ssl, socket); ESP_LOGI(TAG, "SSL connected to %s port %d ......", - OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + OPENSSL_EXAMPLE_TARGET_NAME, OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = SSL_connect(ssl); if (!ret) { ESP_LOGI(TAG, "failed " ); @@ -124,7 +124,7 @@ void openssl_demo_thread(void *p) ESP_LOGI(TAG, "OK"); ESP_LOGI(TAG, "send https request to %s port %d ......", - OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + OPENSSL_EXAMPLE_TARGET_NAME, OPENSSL_EXAMPLE_TARGET_TCP_PORT); ret = SSL_write(ssl, send_data, send_bytes); if (ret <= 0) { ESP_LOGI(TAG, "failed"); @@ -133,7 +133,7 @@ void openssl_demo_thread(void *p) ESP_LOGI(TAG, "OK"); do { - ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + ret = SSL_read(ssl, recv_buf, OPENSSL_EXAMPLE_RECV_BUF_LEN - 1); if (ret <= 0) { break; } @@ -141,7 +141,7 @@ void openssl_demo_thread(void *p) ESP_LOGI(TAG, "%s", recv_buf); } while (1); - ESP_LOGI(TAG, "totaly read %d bytes data from %s ......", recv_bytes, OPENSSL_DEMO_TARGET_NAME); + ESP_LOGI(TAG, "totaly read %d bytes data from %s ......", recv_bytes, OPENSSL_EXAMPLE_TARGET_NAME); failed5: SSL_shutdown(ssl); @@ -159,20 +159,20 @@ failed1: return ; } -static void openssl_client_init(void) +static void openssl_example_client_init(void) { int ret; xTaskHandle openssl_handle; - ret = xTaskCreate(openssl_demo_thread, - OPENSSL_DEMO_THREAD_NAME, - OPENSSL_DEMO_THREAD_STACK_WORDS, + ret = xTaskCreate(openssl_example_task, + OPENSSL_EXAMPLE_TASK_NAME, + OPENSSL_EXAMPLE_TASK_STACK_WORDS, NULL, - OPENSSL_DEMO_THREAD_PRORIOTY, - &openssl_handle); + OPENSSL_EXAMPLE_TASK_PRORIOTY, + &openssl_handle); if (ret != pdPASS) { - ESP_LOGI(TAG, "create thread %s failed", OPENSSL_DEMO_THREAD_NAME); + ESP_LOGI(TAG, "create thread %s failed", OPENSSL_EXAMPLE_TASK_NAME); } } @@ -184,7 +184,7 @@ static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) break; case SYSTEM_EVENT_STA_GOT_IP: xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); - openssl_client_init(); + openssl_example_client_init(); break; case SYSTEM_EVENT_STA_DISCONNECTED: /* This is a workaround as ESP32 WiFi libs don't currently diff --git a/examples/protocols/openssl_server/main/openssl_server.h b/examples/protocols/openssl_server/main/openssl_server_example.h similarity index 75% rename from examples/protocols/openssl_server/main/openssl_server.h rename to examples/protocols/openssl_server/main/openssl_server_example.h index 51708535f..bdb84bae5 100755 --- a/examples/protocols/openssl_server/main/openssl_server.h +++ b/examples/protocols/openssl_server/main/openssl_server_example.h @@ -21,13 +21,13 @@ #define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD -#define OPENSSL_DEMO_THREAD_NAME "OpenSSL_demo" -#define OPENSSL_DEMO_THREAD_STACK_WORDS 10240 -#define OPENSSL_DEMO_THREAD_PRORIOTY 8 +#define OPENSSL_EXAMPLE_TASK_NAME "openssl_example" +#define OPENSSL_EXAMPLE_TASK_STACK_WORDS 10240 +#define OPENSSL_EXAMPLE_TASK_PRORIOTY 8 -#define OPENSSL_DEMO_RECV_BUF_LEN 1024 +#define OPENSSL_EXAMPLE_RECV_BUF_LEN 1024 -#define OPENSSL_DEMO_LOCAL_TCP_PORT 443 +#define OPENSSL_EXAMPLE_LOCAL_TCP_PORT 443 #endif diff --git a/examples/protocols/openssl_server/main/openssl_server.c b/examples/protocols/openssl_server/main/openssl_server_example_main.c similarity index 88% rename from examples/protocols/openssl_server/main/openssl_server.c rename to examples/protocols/openssl_server/main/openssl_server_example_main.c index e1d0619d2..bc0f7c355 100755 --- a/examples/protocols/openssl_server/main/openssl_server.c +++ b/examples/protocols/openssl_server/main/openssl_server_example_main.c @@ -7,7 +7,7 @@ CONDITIONS OF ANY KIND, either express or implied. */ -#include "openssl_server.h" +#include "openssl_server_example.h" #include @@ -33,20 +33,20 @@ static EventGroupHandle_t wifi_event_group; to the AP with an IP? */ const static int CONNECTED_BIT = BIT0; -const static char *TAG = "Openssl_demo"; +const static char *TAG = "Openssl_example"; -#define OPENSSL_DEMO_SERVER_ACK "HTTP/1.1 200 OK\r\n" \ +#define OPENSSL_EXAMPLE_SERVER_ACK "HTTP/1.1 200 OK\r\n" \ "Content-Type: text/html\r\n" \ "Content-Length: 98\r\n\r\n" \ "\r\n" \ "\r\n" \ - "OpenSSL demo\r\n" \ - "OpenSSL server demo!\r\n" \ + "OpenSSL example\r\n" \ + "OpenSSL server example!\r\n" \ "\r\n" \ "\r\n" \ "\r\n" -static void openssl_demo_thread(void *p) +static void openssl_example_task(void *p) { int ret; @@ -57,9 +57,9 @@ static void openssl_demo_thread(void *p) socklen_t addr_len; struct sockaddr_in sock_addr; - char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + char recv_buf[OPENSSL_EXAMPLE_RECV_BUF_LEN]; - const char send_data[] = OPENSSL_DEMO_SERVER_ACK; + const char send_data[] = OPENSSL_EXAMPLE_SERVER_ACK; const int send_bytes = sizeof(send_data); extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); @@ -110,7 +110,7 @@ static void openssl_demo_thread(void *p) memset(&sock_addr, 0, sizeof(sock_addr)); sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = 0; - sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + sock_addr.sin_port = htons(OPENSSL_EXAMPLE_LOCAL_TCP_PORT); ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); if (ret) { ESP_LOGI(TAG, "failed"); @@ -155,8 +155,8 @@ reconnect: ESP_LOGI(TAG, "SSL server read message ......"); do { - memset(recv_buf, 0, OPENSSL_DEMO_RECV_BUF_LEN); - ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + memset(recv_buf, 0, OPENSSL_EXAMPLE_RECV_BUF_LEN); + ret = SSL_read(ssl, recv_buf, OPENSSL_EXAMPLE_RECV_BUF_LEN - 1); if (ret <= 0) { break; } @@ -199,15 +199,15 @@ static void openssl_client_init(void) int ret; xTaskHandle openssl_handle; - ret = xTaskCreate(openssl_demo_thread, - OPENSSL_DEMO_THREAD_NAME, - OPENSSL_DEMO_THREAD_STACK_WORDS, + ret = xTaskCreate(openssl_example_task, + OPENSSL_EXAMPLE_TASK_NAME, + OPENSSL_EXAMPLE_TASK_STACK_WORDS, NULL, - OPENSSL_DEMO_THREAD_PRORIOTY, + OPENSSL_EXAMPLE_TASK_PRORIOTY, &openssl_handle); if (ret != pdPASS) { - ESP_LOGI(TAG, "create thread %s failed", OPENSSL_DEMO_THREAD_NAME); + ESP_LOGI(TAG, "create task %s failed", OPENSSL_EXAMPLE_TASK_NAME); } } diff --git a/examples/protocols/sntp/main/sntp_main.c b/examples/protocols/sntp/main/sntp_example_main.c similarity index 100% rename from examples/protocols/sntp/main/sntp_main.c rename to examples/protocols/sntp/main/sntp_example_main.c diff --git a/examples/storage/nvs_rw_blob/main/nvs_rw_blob.c b/examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c similarity index 100% rename from examples/storage/nvs_rw_blob/main/nvs_rw_blob.c rename to examples/storage/nvs_rw_blob/main/nvs_blob_example_main.c diff --git a/examples/storage/nvs_rw_value/main/nvs_rw_value.c b/examples/storage/nvs_rw_value/main/nvs_value_example_main.c similarity index 100% rename from examples/storage/nvs_rw_value/main/nvs_rw_value.c rename to examples/storage/nvs_rw_value/main/nvs_value_example_main.c diff --git a/examples/storage/sd_card/main/sd_card.c b/examples/storage/sd_card/main/sd_card_example_main.c similarity index 100% rename from examples/storage/sd_card/main/sd_card.c rename to examples/storage/sd_card/main/sd_card_example_main.c diff --git a/examples/system/deep_sleep/main/deep_sleep_wakeup.c b/examples/system/deep_sleep/main/deep_sleep_example_main.c similarity index 100% rename from examples/system/deep_sleep/main/deep_sleep_wakeup.c rename to examples/system/deep_sleep/main/deep_sleep_example_main.c diff --git a/examples/system/ota/main/ota_example.c b/examples/system/ota/main/ota_example_main.c similarity index 97% rename from examples/system/ota/main/ota_example.c rename to examples/system/ota/main/ota_example_main.c index bc910f70c..bb931ae0a 100644 --- a/examples/system/ota/main/ota_example.c +++ b/examples/system/ota/main/ota_example_main.c @@ -135,7 +135,7 @@ static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t u return false; } -bool connect_to_http_server() +static bool connect_to_http_server() { ESP_LOGI(TAG, "Server IP: %s Server Port:%s", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT); sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT); @@ -168,7 +168,7 @@ bool connect_to_http_server() return false; } -void __attribute__((noreturn)) task_fatal_error() +static void __attribute__((noreturn)) task_fatal_error() { ESP_LOGE(TAG, "Exiting task due to fatal error..."); close(socket_id); @@ -179,7 +179,7 @@ void __attribute__((noreturn)) task_fatal_error() } } -void main_task(void *pvParameter) +static void ota_example_task(void *pvParameter) { esp_err_t err; /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */ @@ -295,5 +295,5 @@ void app_main() ESP_ERROR_CHECK( err ); initialise_wifi(); - xTaskCreate(&main_task, "main_task", 8192, NULL, 5, NULL); + xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL); } diff --git a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c index 0932aec93..d2b6344ec 100644 --- a/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c +++ b/examples/wifi/wpa2_enterprise/main/wpa2_enterprise_main.c @@ -127,7 +127,7 @@ static void initialise_wifi(void) ESP_ERROR_CHECK( esp_wifi_start() ); } -static void wpa2_enterprise_task(void *pvParameters) +static void wpa2_enterprise_example_task(void *pvParameters) { tcpip_adapter_ip_info_t ip; memset(&ip, 0, sizeof(tcpip_adapter_ip_info_t)); @@ -150,5 +150,5 @@ void app_main() { ESP_ERROR_CHECK( nvs_flash_init() ); initialise_wifi(); - xTaskCreate(&wpa2_enterprise_task, "wpa2_enterprise_task", 4096, NULL, 5, NULL); + xTaskCreate(&wpa2_enterprise_example_task, "wpa2_enterprise_example_task", 4096, NULL, 5, NULL); } From 76295c7a13a9aa53538b0915e81999862d871ccd Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Thu, 2 Mar 2017 18:46:59 +0800 Subject: [PATCH 50/57] Fix timing adjustment needed for higher speeds of SPI master bus. --- components/driver/include/driver/spi_master.h | 3 + components/driver/spi_master.c | 43 +++++++++++--- components/driver/test/test_spi_master.c | 57 +++++++++++-------- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/components/driver/include/driver/spi_master.h b/components/driver/include/driver/spi_master.h index 83110d9d0..d78f5ea0b 100644 --- a/components/driver/include/driver/spi_master.h +++ b/components/driver/include/driver/spi_master.h @@ -153,6 +153,9 @@ esp_err_t spi_bus_free(spi_host_device_t host); * peripheral and routes it to the indicated GPIO. All SPI master devices have three CS pins and can thus control * up to three devices. * + * @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are + * supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz. + * * @param host SPI peripheral to allocate device on * @param dev_config SPI interface protocol config for the device * @param handle Pointer to variable to hold the device handle diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 17a68c323..723fbdb03 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -268,7 +268,9 @@ esp_err_t spi_bus_initialize(spi_host_device_t host, spi_bus_config_t *bus_confi spihost[host]->hw->dma_out_link.start=0; spihost[host]->hw->dma_in_link.start=0; spihost[host]->hw->dma_conf.val&=~(SPI_OUT_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST); - + //Reset timing + spihost[host]->hw->ctrl2.val=0; + //Disable unneeded ints spihost[host]->hw->slave.rd_buf_done=0; spihost[host]->hw->slave.wr_buf_done=0; @@ -315,6 +317,7 @@ esp_err_t spi_bus_free(spi_host_device_t host) esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config_t *dev_config, spi_device_handle_t *handle) { int freecs; + int apbclk=APB_CLK_FREQ; SPI_CHECK(host>=SPI_HOST && host<=VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG); SPI_CHECK(spihost[host]!=NULL, "host not initialized", ESP_ERR_INVALID_STATE); SPI_CHECK(dev_config->spics_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num), "spics pin invalid", ESP_ERR_INVALID_ARG); @@ -327,6 +330,9 @@ esp_err_t spi_bus_add_device(spi_host_device_t host, spi_device_interface_config //The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full //duplex mode does absolutely nothing on the ESP32. SPI_CHECK(dev_config->cs_ena_pretrans==0 || (dev_config->flags & SPI_DEVICE_HALFDUPLEX), "cs pretrans delay incompatible with full-duplex", ESP_ERR_INVALID_ARG); + //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. + SPI_CHECK(!( ((dev_config->flags & SPI_DEVICE_HALFDUPLEX)==0) && (dev_config->clock_speed_hz > ((apbclk*2)/5)) && (!spihost[host]->no_gpio_matrix)), + "No speeds >26MHz supported for full-duplex, GPIO-matrix SPI transfers", ESP_ERR_INVALID_ARG); //Allocate memory for device spi_device_t *dev=malloc(sizeof(spi_device_t)); @@ -394,8 +400,12 @@ static int spi_freq_for_pre_n(int fapb, int pre, int n) { return (fapb / (pre * n)); } -static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { - int pre, n, h, l; +/* + * Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly + * different from the requested frequency. + */ +static int spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { + int pre, n, h, l, eff_clk; //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. if (hz>((fapb/4)*3)) { @@ -405,6 +415,7 @@ static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { hw->clock.clkcnt_n=0; hw->clock.clkdiv_pre=0; hw->clock.clk_equ_sysclk=1; + eff_clk=fapb; } else { //For best duty cycle resolution, we want n to be as close to 32 as possible, but //we also need a pre/n combo that gets us as close as possible to the intended freq. @@ -440,7 +451,9 @@ static void spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { hw->clock.clkdiv_pre=pre-1; hw->clock.clkcnt_h=h-1; hw->clock.clkcnt_l=l-1; + eff_clk=spi_freq_for_pre_n(fapb, pre, n); } + return eff_clk; } @@ -516,14 +529,28 @@ static void IRAM_ATTR spi_intr(void *arg) //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have //clock scaling working. int apbclk=APB_CLK_FREQ; - spi_set_clock(host->hw, apbclk, dev->cfg.clock_speed_hz, dev->cfg.duty_cycle_pos); + int effclk=spi_set_clock(host->hw, apbclk, dev->cfg.clock_speed_hz, dev->cfg.duty_cycle_pos); //Configure bit order host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0; host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0; //Configure polarity - //SPI iface needs to be configured for a delay unless it is not routed through GPIO and clock is >=apb/2 - int nodelay=(host->no_gpio_matrix && dev->cfg.clock_speed_hz >= (apbclk/2)); + //SPI iface needs to be configured for a delay in some cases. + int nodelay=0; + int extra_dummy=0; + if (host->no_gpio_matrix) { + if (effclk >= apbclk/2) { + nodelay=1; + } + } else { + if (effclk >= apbclk/2) { + nodelay=1; + extra_dummy=1; //Note: This only works on half-duplex connections. spi_bus_add_device checks for this. + } else if (effclk >= apbclk/4) { + nodelay=1; + } + } + if (dev->cfg.mode==0) { host->hw->pin.ck_idle_edge=0; host->hw->user.ck_out_edge=0; @@ -543,11 +570,11 @@ static void IRAM_ATTR spi_intr(void *arg) } //Configure bit sizes, load addr and command - host->hw->user.usr_dummy=(dev->cfg.dummy_bits)?1:0; + host->hw->user.usr_dummy=(dev->cfg.dummy_bits+extra_dummy)?1:0; host->hw->user.usr_addr=(dev->cfg.address_bits)?1:0; host->hw->user.usr_command=(dev->cfg.command_bits)?1:0; host->hw->user1.usr_addr_bitlen=dev->cfg.address_bits-1; - host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits-1; + host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits+extra_dummy-1; host->hw->user2.usr_command_bitlen=dev->cfg.command_bits-1; //Configure misc stuff host->hw->user.doutdin=(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1; diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index cb04af8c9..f88427a81 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -80,41 +80,29 @@ TEST_CASE("SPI Master clockdiv calculation routines", "[spi]") } -TEST_CASE("SPI Master test", "[spi][ignore]") -{ - spi_bus_config_t buscfg={ - .mosi_io_num=4, - .miso_io_num=16, - .sclk_io_num=25, - .quadwp_io_num=-1, - .quadhd_io_num=-1 - }; +static void test_spi_bus_speed(int hz) { + esp_err_t ret; + spi_device_handle_t handle; spi_device_interface_config_t devcfg={ .command_bits=8, .address_bits=64, .dummy_bits=0, - .clock_speed_hz=8000, + .clock_speed_hz=hz, .duty_cycle_pos=128, .mode=0, .spics_io_num=21, - .queue_size=3 + .queue_size=3, }; - esp_err_t ret; - spi_device_handle_t handle; - printf("THIS TEST NEEDS A JUMPER BETWEEN IO4 AND IO16\n"); - - ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1); - TEST_ASSERT(ret==ESP_OK); ret=spi_bus_add_device(HSPI_HOST, &devcfg, &handle); TEST_ASSERT(ret==ESP_OK); printf("Bus/dev inited.\n"); spi_transaction_t t; - char sendbuf[16]="Hello World!"; - char recvbuf[16]="UUUUUUUUUUUUUUU"; + char sendbuf[64]="Hello World!"; + char recvbuf[64]="UUUUUUUUUUUUUUU"; memset(&t, 0, sizeof(t)); - t.length=16*8; + t.length=64*8; t.tx_buffer=sendbuf; t.rx_buffer=recvbuf; t.address=0xA00000000000000FL; @@ -130,11 +118,32 @@ TEST_CASE("SPI Master test", "[spi][ignore]") ret=spi_bus_remove_device(handle); TEST_ASSERT(ret==ESP_OK); - ret=spi_bus_free(HSPI_HOST); - TEST_ASSERT(ret==ESP_OK); - - TEST_ASSERT_EQUAL_INT8_ARRAY(sendbuf, recvbuf, 16); + TEST_ASSERT_EQUAL_INT8_ARRAY(sendbuf, recvbuf, 64); } +TEST_CASE("SPI Master test", "[spi][ignore]") +{ + spi_bus_config_t buscfg={ + .mosi_io_num=4, + .miso_io_num=16, + .sclk_io_num=25, + .quadwp_io_num=-1, + .quadhd_io_num=-1 + }; + esp_err_t ret; + printf("THIS TEST NEEDS A JUMPER BETWEEN IO4 AND IO16\n"); + + ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1); + TEST_ASSERT(ret==ESP_OK); + + int freqs[]={8000, 1000000, 5000000, 10000000, 20000000, 26666666, 0}; + for (int x=0; freqs[x]!=0; x++) { + printf("Testing clock speed of %dHz...\n", freqs[x]); + test_spi_bus_speed(freqs[x]); + } + + ret=spi_bus_free(HSPI_HOST); + TEST_ASSERT(ret==ESP_OK); +} From dbb6d20aac0be134987ca73d45a73bdc248605a8 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 28 Mar 2017 14:22:27 +0800 Subject: [PATCH 51/57] make: remove version parameter from git status porcelain option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version parameter was added in git 2.11, while default git on macOS is currently 2.10. According to the latest git docs, if the version parameter is not provided, it defaults to ‘v1’, so removing it doesn’t change the format. --- make/project.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/project.mk b/make/project.mk index 6c3bc6b1e..4a2c39aa9 100644 --- a/make/project.mk +++ b/make/project.mk @@ -405,7 +405,7 @@ clean: config-clean check-submodules: # Dump the git status for the whole working copy once, then grep it for each submodule. This saves a lot of time on Windows. -GIT_STATUS := $(shell cd ${IDF_PATH} && git status --porcelain=v1 --ignore-submodules=dirty) +GIT_STATUS := $(shell cd ${IDF_PATH} && git status --porcelain --ignore-submodules=dirty) # Generate a target to check this submodule # $(1) - submodule directory, relative to IDF_PATH From 0e39b77d4ec180e753cf1e142b70dab489953265 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 28 Mar 2017 15:50:10 +0800 Subject: [PATCH 52/57] Fix finding location of ISR stack space for CPU1 --- components/freertos/portasm.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/freertos/portasm.S b/components/freertos/portasm.S index ad65a103e..7f23e6283 100644 --- a/components/freertos/portasm.S +++ b/components/freertos/portasm.S @@ -132,8 +132,8 @@ _frxt_int_enter: l32i a2, a2, 0 /* a2 = current TCB */ beqz a2, 1f s32i a1, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */ - movi a1, port_IntStackTop /* a1 = top of intr stack */ - movi a2, configISR_STACK_SIZE + movi a1, port_IntStack+configISR_STACK_SIZE /* a1 = top of intr stack for CPU 0 */ + movi a2, configISR_STACK_SIZE /* add configISR_STACK_SIZE * cpu_num to arrive at top of stack for cpu_num */ mull a2, a4, a2 add a1, a1, a2 /* for current proc */ From 96e8a3c725095562d2725aaefa15adcfc5d78dd5 Mon Sep 17 00:00:00 2001 From: negativekelvin Date: Mon, 13 Feb 2017 21:53:46 -0700 Subject: [PATCH 53/57] mdns: add simple dns-sd meta query support tabs to spaces match domain --- components/mdns/mdns.c | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/components/mdns/mdns.c b/components/mdns/mdns.c index d0fc69c4c..953ed64b9 100644 --- a/components/mdns/mdns.c +++ b/components/mdns/mdns.c @@ -46,6 +46,7 @@ #define MDNS_ANSWER_A 0x01 #define MDNS_ANSWER_AAAA 0x10 #define MDNS_ANSWER_NSEC 0x20 +#define MDNS_ANSWER_SDPTR 0x80 #define MDNS_SERVICE_PORT 5353 // UDP port that the server runs on #define MDNS_SERVICE_STACK_DEPTH 4096 // Stack size for the service thread @@ -796,6 +797,52 @@ static uint16_t _mdns_append_ptr_record(uint8_t * packet, uint16_t * index, mdns return record_length; } +/** + * @brief appends DNS-SD PTR record for service to a packet, incrementing the index + * + * @param packet MDNS packet + * @param index offset in the packet + * @param server the server that is hosting the service + * @param service the service to add record for + * + * @return length of added data: 0 on error or length on success + */ +static uint16_t _mdns_append_sdptr_record(uint8_t * packet, uint16_t * index, mdns_server_t * server, mdns_service_t * service) +{ + const char * str[3]; + const char * sd_str[4]; + uint16_t record_length = 0; + uint8_t part_length; + + sd_str[0] = (char*)"_services"; + sd_str[1] = (char*)"_dns-sd"; + sd_str[2] = (char*)"_udp"; + sd_str[3] = MDNS_DEFAULT_DOMAIN; + + str[0] = service->service; + str[1] = service->proto; + str[2] = MDNS_DEFAULT_DOMAIN; + + part_length = _mdns_append_fqdn(packet, index, sd_str, 4); + + record_length += part_length; + + part_length = _mdns_append_type(packet, index, MDNS_ANSWER_PTR, MDNS_ANSWER_PTR_TTL); + if (!part_length) { + return 0; + } + record_length += part_length; + + uint16_t data_len_location = *index - 2; + part_length = _mdns_append_fqdn(packet, index, str, 3); + if (!part_length) { + return 0; + } + _mdns_set_u16(packet, data_len_location, part_length); + record_length += part_length; + return record_length; +} + /** * @brief appends TXT record for service to a packet, incrementing the index * @@ -1042,6 +1089,13 @@ static void _mdns_send_answers(mdns_server_t * server, mdns_answer_item_t * answ } answer_count += 1; } + + if (answers->answer & MDNS_ANSWER_SDPTR) { + if (!_mdns_append_sdptr_record(packet, &index, server, answers->service)) { + return; + } + answer_count += 1; + } } mdns_answer_item_t * a = answers; answers = answers->next; @@ -1274,6 +1328,20 @@ static void _mdns_parse_packet(mdns_server_t * server, const uint8_t * data, siz } continue; } + + //is this a dns-sd service discovery meta query? + if (!strcmp(name->host, "_services") && !strcmp(name->service, "_dns-sd") && !strcmp(name->proto, "_udp") && !strcmp(name->domain, MDNS_DEFAULT_DOMAIN) && type == MDNS_TYPE_PTR) + { + //add answers for all services + mdns_srv_item_t * s = server->services; + while(s) { + if (s->service->service && s->service->proto) { + answers = _mdns_add_answer(answers, s->service, MDNS_ANSWER_SDPTR); + } + s = s->next; + } + continue; + } if (name->sub) { continue; From 987631b9a0db8eedfb7d2c9de8006e7c32e0c394 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Mar 2017 10:58:58 +1100 Subject: [PATCH 54/57] windows: Don't expand PATH when generating setup Ref #467 https://github.com/espressif/esp-idf/issues/467 --- docs/windows-setup.rst | 2 +- tools/windows/windows_install_prerequisites.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index 16b46732a..9c90d9183 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -8,7 +8,7 @@ Windows doesn't have a built-in "make" environment, so as well as installing the The quick setup is to download the Windows all-in-one toolchain & MSYS zip file from dl.espressif.com: -https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20170321.zip +https://dl.espressif.com/dl/esp32_win32_msys2_environment_and_toolchain-20170330.zip Unzip the zip file to ``C:\`` (or some other location, but this guide assumes ``C:\``) and it will create an "msys32" directory with a pre-prepared environment. diff --git a/tools/windows/windows_install_prerequisites.sh b/tools/windows/windows_install_prerequisites.sh index 1b3f39059..b4d633768 100644 --- a/tools/windows/windows_install_prerequisites.sh +++ b/tools/windows/windows_install_prerequisites.sh @@ -51,7 +51,7 @@ rm ~/${TOOLCHAIN_ZIP} cat > /etc/profile.d/esp32_toolchain.sh << EOF # This file was created by ESP-IDF windows_install_prerequisites.sh # and will be overwritten if that script is run again. -export PATH="$PATH:/opt/xtensa-esp32-elf/bin" +export PATH="\$PATH:/opt/xtensa-esp32-elf/bin" EOF # clean up pacman packages to save some disk space From c0fb62531e34aace1afd7491a9a6ad5713aba934 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 30 Mar 2017 11:29:03 +1100 Subject: [PATCH 55/57] doc: Fix some Windows Setup Guide links --- docs/windows-setup-scratch.rst | 2 ++ docs/windows-setup.rst | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/windows-setup-scratch.rst b/docs/windows-setup-scratch.rst index 2037a21da..07cd51ecd 100644 --- a/docs/windows-setup-scratch.rst +++ b/docs/windows-setup-scratch.rst @@ -63,3 +63,5 @@ Or with credentials:: export http_proxy='http://user:password@http.proxy.server:PORT' Add this line to ``/etc/profile`` in the MSYS directory in order to permanently enable the proxy when using MSYS. + +.. _MSYS2: https://msys2.github.io/ diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index 9c90d9183..603776168 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -4,7 +4,7 @@ Set up of Toolchain for Windows Step 1: Quick Steps =================== -Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide this. You don't need to use this environment all the time (you can use Eclipse_ or some other front-end), but it runs behind the scenes. +Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide this. You don't need to use this environment all the time (you can use :doc:`Eclipse ` or some other front-end), but it runs behind the scenes. The quick setup is to download the Windows all-in-one toolchain & MSYS zip file from dl.espressif.com: @@ -62,10 +62,8 @@ Type a command like this to set the path to ESP-IDF directory: ``export IDF_PATH Use ``cd`` to change to the project directory (not the ESP-IDF directory.) Type ``make menuconfig`` to configure your project, then ``make`` to build it, ``make clean`` to remove built files, and ``make flash`` to flash (use the menuconfig to set the serial port for flashing.) -If you'd like to use the Eclipse IDE instead of running ``make``, check out the Eclipse setup guide in this directory. +If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. -.. _Eclipse: eclipse-setup.rst -.. _MSYS2: https://msys2.github.io/ .. _github: https://github.com/espressif/esp-idf-template .. _known issue: https://github.com/espressif/esp-idf/issues/11 From c690447dd9abbcb805c7c4c2fb5a89d9296372e2 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Thu, 16 Mar 2017 16:20:19 +0800 Subject: [PATCH 56/57] wifi scan: add wifi scan type and time config --- components/esp32/include/esp_wifi.h | 2 ++ components/esp32/include/esp_wifi_types.h | 27 +++++++++++++++++++---- components/esp32/lib | 2 +- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index a9b072200..f48146b25 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -296,6 +296,8 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid); * @attention If this API is called, the found APs are stored in WiFi driver dynamic allocated memory and the * will be freed in esp_wifi_get_ap_list, so generally, call esp_wifi_get_ap_list to cause * the memory to be freed once the scan is done + * @attention The values of maximum active scan time and passive scan time per channel are limited to 1500 milliseconds. + * Values above 1500ms may cause station to disconnect from AP and are not recommended. * * @param config configuration of scanning * @param block if block is true, this API will block the caller until the scan is done, otherwise diff --git a/components/esp32/include/esp_wifi_types.h b/components/esp32/include/esp_wifi_types.h index 2b30f5b8b..be5435da0 100755 --- a/components/esp32/include/esp_wifi_types.h +++ b/components/esp32/include/esp_wifi_types.h @@ -96,11 +96,30 @@ typedef enum { WIFI_SECOND_CHAN_BELOW, /**< the channel width is HT40 and the second channel is below the primary channel */ } wifi_second_chan_t; +typedef enum { + WIFI_SCAN_TYPE_ACTIVE = 0, /**< active scan */ + WIFI_SCAN_TYPE_PASSIVE, /**< passive scan */ +} wifi_scan_type_t; + typedef struct { - uint8_t *ssid; /**< SSID of AP */ - uint8_t *bssid; /**< MAC address of AP */ - uint8_t channel; /**< channel, scan the specific channel */ - bool show_hidden; /**< enable to scan AP whose SSID is hidden */ + uint32_t min; /**< minimum active scan time per channel, units: millisecond */ + uint32_t max; /**< maximum active scan time per channel, units: millisecond, values above 1500ms may + cause station to disconnect from AP and are not recommended. */ +} wifi_active_scan_time_t; + +typedef union { + wifi_active_scan_time_t active; /**< active scan time per channel */ + uint32_t passive; /**< passive scan time per channel, units: millisecond, values above 1500ms may + cause station to disconnect from AP and are not recommended. */ +} wifi_scan_time_t; + +typedef struct { + uint8_t *ssid; /**< SSID of AP */ + uint8_t *bssid; /**< MAC address of AP */ + uint8_t channel; /**< channel, scan the specific channel */ + bool show_hidden; /**< enable to scan AP whose SSID is hidden */ + wifi_scan_type_t scan_type; /**< scan type, active or passive */ + wifi_scan_time_t scan_time; /**< scan time per channel */ } wifi_scan_config_t; typedef struct { diff --git a/components/esp32/lib b/components/esp32/lib index 5c98c5a8b..bd53ad194 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 5c98c5a8b93dbf181849b40c6d6cd164a52bfc4c +Subproject commit bd53ad194dd85885d3d41f455e9debeb9409aef9 From 4f89cc73e6f6f207e97afff873139b700cfb5ca3 Mon Sep 17 00:00:00 2001 From: XiaXiaotian Date: Tue, 14 Mar 2017 21:03:41 +0800 Subject: [PATCH 57/57] Add WiFi static and dynamic tx buffer choice If static tx buffer is selected, WiFi tx buffers are allocated when WiFi is initialized and released when WiFi is de-initialized. If dynamic tx buffer is selected, WiFi tx buffer is allocated when tx data is delivered from LWIP to WiFi and released when tx data is sent out by WiFi. The size of each static tx buffers is fixed to about 1.6KB and the size of dynamic tx buffers is depend on the length of the data delivered from LWIP. If PSRAM is enabled, "STATIC" should be selected to guarantee enough WiFi tx buffers. If PSRAM is disabled, "DYNAMIC" should be selected to improve the utilization of RAM. --- components/esp32/Kconfig | 44 +++++++++++++++++++++++++++-- components/esp32/include/esp_wifi.h | 18 +++++++++++- components/esp32/lib | 2 +- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index ab1e04e80..a156b85c9 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -541,9 +541,50 @@ config ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM number. Generally the number of dynamic rx buffer should be no less than static rx buffer number if it is not 0. +choice ESP32_WIFI_TX_BUFFER + prompt "Type of WiFi TX buffers" + depends on WIFI_ENABLED + default ESP32_WIFI_DYNAMIC_TX_BUFFER + help + Select type of WiFi tx buffers and show the submenu with the number of WiFi tx buffers choice. + If "STATIC" is selected, WiFi tx buffers are allocated when WiFi is initialized and released + when WiFi is de-initialized. If "DYNAMIC" is selected, WiFi tx buffer is allocated when tx + data is delivered from LWIP to WiFi and released when tx data is sent out by WiFi. + The size of each static tx buffers is fixed to about 1.6KB and the size of dynamic tx buffers is + depend on the length of the data delivered from LWIP. + If PSRAM is enabled, "STATIC" should be selected to guarantee enough WiFi tx buffers. + If PSRAM is disabled, "DYNAMIC" should be selected to improve the utilization of RAM. + +config ESP32_WIFI_STATIC_TX_BUFFER + bool "STATIC" +config ESP32_WIFI_DYNAMIC_TX_BUFFER + bool "DYNAMIC" +endchoice + +config ESP32_WIFI_TX_BUFFER_TYPE + int + depends on WIFI_ENABLED + default 0 if ESP32_WIFI_STATIC_TX_BUFFER + default 1 if ESP32_WIFI_DYNAMIC_TX_BUFFER + +config ESP32_WIFI_STATIC_TX_BUFFER_NUM + int "Max number of WiFi static TX buffers" + depends on WIFI_ENABLED + depends on ESP32_WIFI_STATIC_TX_BUFFER + range 16 64 + default 32 + help + Set the number of WiFi static tx buffers. Each buffer takes approximately 1.6KB of RAM. + The static rx buffers are allocated when esp_wifi_init is called, they are not released + until esp_wifi_deinit is called. + For each tx packet from high layer stack, WiFi driver make a copy of it. For some applications, + especially the UDP application, the high layer deliver speed is faster than the WiFi tx + speed, we may run out of static tx buffers. + config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM int "Max number of WiFi dynamic TX buffers" - depends on WIFI_ENABLED + depends on WIFI_ENABLED + depends on ESP32_WIFI_DYNAMIC_TX_BUFFER range 16 64 default 32 help @@ -553,7 +594,6 @@ config ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM especially the UDP application, the high layer deliver speed is faster than the WiFi tx speed, we may run out of memory if no limitation for the dynamic tx buffer number. - config ESP32_WIFI_AMPDU_ENABLED bool "WiFi AMPDU" depends on WIFI_ENABLED diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index f48146b25..88a477f12 100755 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -97,6 +97,8 @@ typedef struct { system_event_handler_t event_handler; /**< WiFi event handler */ int static_rx_buf_num; /**< WiFi static RX buffer number */ int dynamic_rx_buf_num; /**< WiFi dynamic RX buffer number */ + int tx_buf_type; /**< WiFi TX buffer type */ + int static_tx_buf_num; /**< WiFi static TX buffer number */ int dynamic_tx_buf_num; /**< WiFi dynamic TX buffer number */ int ampdu_enable; /**< WiFi AMPDU feature enable flag */ int nvs_enable; /**< WiFi NVS flash enable flag */ @@ -104,6 +106,18 @@ typedef struct { int magic; /**< WiFi init magic number, it should be the last field */ } wifi_init_config_t; +#ifdef CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM +#define WIFI_STATIC_TX_BUFFER_NUM CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM +#else +#define WIFI_STATIC_TX_BUFFER_NUM 0 +#endif + +#ifdef CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM +#define WIFI_DYNAMIC_TX_BUFFER_NUM CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM +#else +#define WIFI_DYNAMIC_TX_BUFFER_NUM 0 +#endif + #if CONFIG_ESP32_WIFI_AMPDU_ENABLED #define WIFI_AMPDU_ENABLED 1 #else @@ -128,7 +142,9 @@ typedef struct { .event_handler = &esp_event_send, \ .static_rx_buf_num = CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM,\ .dynamic_rx_buf_num = CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM,\ - .dynamic_tx_buf_num = CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM,\ + .tx_buf_type = CONFIG_ESP32_WIFI_TX_BUFFER_TYPE,\ + .static_tx_buf_num = WIFI_STATIC_TX_BUFFER_NUM,\ + .dynamic_tx_buf_num = WIFI_DYNAMIC_TX_BUFFER_NUM,\ .ampdu_enable = WIFI_AMPDU_ENABLED,\ .nvs_enable = WIFI_NVS_ENABLED,\ .nano_enable = WIFI_NANO_FORMAT_ENABLED,\ diff --git a/components/esp32/lib b/components/esp32/lib index bd53ad194..ae20d8efc 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit bd53ad194dd85885d3d41f455e9debeb9409aef9 +Subproject commit ae20d8efce9c46dea9dc949b542d8dfaa3ea136c