diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 3e03ba91..b85b2887 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -119,31 +119,40 @@ config BOOTLOADER_DATA_FACTORY_RESET default "nvs" help Allows customers to select which data partitions will be erased while factory reset. - + Specify the names of partitions as a comma-delimited with optional spaces for readability. (Like this: "nvs, phy_init, ...") Make sure that the name specified in the partition table and here are the same. Partitions of type "app" cannot be specified here. config BOOTLOADER_APP_TEST bool "GPIO triggers boot from test app partition" - default N - depends on TARGET_PLATFORM_ESP32 + default n help Allows to run the test app from "TEST" partition. A boot from "test" partition will occur if there is a GPIO input pulled low while device starts up. See settings below. +config BOOTLOADER_APP_TEST_IN_OTA_1 + depends on BOOTLOADER_APP_TEST && TARGET_PLATFORM_ESP8266 + bool "Put test app in the ota_1 partition" + default y + help + For the small SPI Flash solution, there maybe no enough space for the test app partition. + By enable this option, test app will locate in ota_1 partition by default. + After ota, the test app will be erased and re-write as new app. + + If you disable this, make sure there has a test app partition in you partition table CVS. + config BOOTLOADER_NUM_PIN_APP_TEST int "Number of the GPIO input to boot TEST partition" depends on BOOTLOADER_APP_TEST - range 0 39 - default 18 + range 0 15 + default 2 help The selected GPIO will be configured as an input with internal pull-up enabled. - To trigger a test app, this GPIO must be pulled low on reset. + To trigger a test app(the second ota firmware), this GPIO must be pulled low on reset. After the GPIO input is deactivated and the device reboots, the old application will boot. (factory or OTA[x]). - Note that GPIO34-39 do not have an internal pullup and an external one must be provided. config BOOTLOADER_HOLD_TIME_GPIO int "Hold time of GPIO for reset/test mode (seconds)" diff --git a/components/bootloader/subproject/main/bootloader_start.c b/components/bootloader/subproject/main/bootloader_start.c index b5c68ea3..b748d7fc 100644 --- a/components/bootloader/subproject/main/bootloader_start.c +++ b/components/bootloader/subproject/main/bootloader_start.c @@ -18,6 +18,7 @@ #include "bootloader_config.h" #include "bootloader_init.h" #include "bootloader_utility.h" +#include "bootloader_common.h" #include "esp_image_format.h" #include "esp_log.h" @@ -97,6 +98,11 @@ static int selected_boot_partition(const bootloader_state_t *bs) #ifdef CONFIG_BOOTLOADER_APP_TEST if (bootloader_common_check_long_hold_gpio(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST, CONFIG_BOOTLOADER_HOLD_TIME_GPIO) == 1) { ESP_LOGI(TAG, "Detect a boot condition of the test firmware"); +#ifdef CONFIG_BOOTLOADER_APP_TEST_IN_OTA_1 + /* In this case, test bin will locate in ota_1 by default. + This is the solution for small Flash. */ + return 1; +#else if (bs->test.offset != 0) { boot_index = TEST_APP_INDEX; return boot_index; @@ -104,6 +110,7 @@ static int selected_boot_partition(const bootloader_state_t *bs) ESP_LOGE(TAG, "Test firmware is not found in partition table"); return INVALID_INDEX; } +#endif } #endif // Customer implementation. diff --git a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld index a9e48559..7f4e15cd 100644 --- a/components/bootloader/subproject/main/esp8266.bootloader.rom.ld +++ b/components/bootloader/subproject/main/esp8266.bootloader.rom.ld @@ -2,6 +2,8 @@ PROVIDE ( ets_memcpy = 0x400018b4 ); PROVIDE ( SPIRead = 0x40004b1c ); +PROVIDE ( gpio_input_get = 0x40004cf0 ); + PROVIDE ( xthal_get_ccount = 0x4000dd38 ); PROVIDE ( uart_div_modify = 0x400039d8 ); PROVIDE ( ets_io_vprintf = 0x40001f00 ); \ No newline at end of file diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index 1772a978..823af3f7 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -165,11 +165,23 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat #include #include +#include + #include "esp_err.h" #include "esp_log.h" #include "crc.h" +#include "rom/gpio.h" + #include "bootloader_config.h" +#include "bootloader_common.h" + +static const char *TAG = "bootloader_common"; + +static inline uint32_t esp_log_early_timestamp() +{ + return xthal_get_ccount() / (80 * 1000); +} uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s) { @@ -181,4 +193,24 @@ bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s) return s->ota_seq != UINT32_MAX && s->crc == bootloader_common_ota_select_crc(s); } +esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec) +{ + gpio_pad_select_gpio(num_pin); + gpio_pad_pullup(num_pin); + + uint32_t tm_start = esp_log_early_timestamp(); + if (GPIO_INPUT_GET(num_pin) == 1) { + ESP_LOGD(TAG, "gpio %d input %x", num_pin, GPIO_INPUT_GET(num_pin)); + return GPIO_NOT_HOLD; + } + do { + if (GPIO_INPUT_GET(num_pin) != 0) { + ESP_LOGD(TAG, "gpio %d input %x", num_pin, GPIO_INPUT_GET(num_pin)); + return GPIO_SHORT_HOLD; + } + } while (delay_sec > ((esp_log_early_timestamp() - tm_start) / 1000L)); + ESP_LOGD(TAG, "gpio %d input %x", num_pin, GPIO_INPUT_GET(num_pin)); + return GPIO_LONG_HOLD; +} + #endif diff --git a/components/esp8266/include/esp8266/pin_mux_register.h b/components/esp8266/include/esp8266/pin_mux_register.h index a7884463..06db930c 100644 --- a/components/esp8266/include/esp8266/pin_mux_register.h +++ b/components/esp8266/include/esp8266/pin_mux_register.h @@ -151,4 +151,23 @@ SET_PERI_REG_MASK(PIN_NAME, (((FUNC & BIT2) << 2) | (FUNC & 0x3)) << PERIPHS_IO_MUX_FUNC_S); \ } while (0) +#define PERIPHS_GPIO_MUX_REG(i) \ + (i==0) ? PERIPHS_IO_MUX_GPIO0_U: \ + (i==1) ? PERIPHS_IO_MUX_U0TXD_U: \ + (i==2) ? PERIPHS_IO_MUX_GPIO2_U: \ + (i==3) ? PERIPHS_IO_MUX_U0RXD_U: \ + (i==4) ? PERIPHS_IO_MUX_GPIO4_U: \ + (i==5) ? PERIPHS_IO_MUX_GPIO5_U: \ + (i==6) ? PERIPHS_IO_MUX_SD_CLK_U: \ + (i==7) ? PERIPHS_IO_MUX_SD_DATA0_U: \ + (i==8) ? PERIPHS_IO_MUX_SD_DATA1_U: \ + (i==9) ? PERIPHS_IO_MUX_SD_DATA2_U: \ + (i==10)? PERIPHS_IO_MUX_SD_DATA3_U: \ + (i==11)? PERIPHS_IO_MUX_SD_CMD_U: \ + (i==12)? PERIPHS_IO_MUX_MTDI_U: \ + (i==13)? PERIPHS_IO_MUX_MTCK_U: \ + (i==14)? PERIPHS_IO_MUX_MTMS_U: \ + (i==15)? PERIPHS_IO_MUX_MTDO_U: \ + PAD_XPD_DCDC_CONF + #endif //_PIN_MUX_H_ diff --git a/components/esp8266/include/rom/gpio.h b/components/esp8266/include/rom/gpio.h new file mode 100644 index 00000000..2ea50ca9 --- /dev/null +++ b/components/esp8266/include/rom/gpio.h @@ -0,0 +1,102 @@ +// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef _ROM_GPIO_H_ +#define _ROM_GPIO_H_ + +#include + +#include "esp8266/pin_mux_register.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup gpio_apis, uart configuration and communication related apis + * @brief gpio apis + */ + +/** @addtogroup gpio_apis + * @{ + */ + +#define GPIO_INPUT_GET(gpio_no) ((gpio_input_get() >> (gpio_no)) & BIT0) + +/** + * @brief Change GPIO(0-15) pin output by setting, clearing, or disabling pins, GPIO0<->BIT(0). + * There is no particular ordering guaranteed; so if the order of writes is significant, + * calling code should divide a single call into multiple calls. + * + * @param uint32_t set_mask : the gpios that need high level. + * + * @param uint32_t clear_mask : the gpios that need low level. + * + * @param uint32_t enable_mask : the gpios that need be changed. + * + * @param uint32_t disable_mask : the gpios that need diable output. + * + * @return None + */ +void gpio_output_set(uint32_t set_mask, uint32_t clear_mask, uint32_t enable_mask, uint32_t disable_mask); + +/** + * @brief Sample the value of GPIO input pins(0-31) and returns a bitmask. + * + * @param None + * + * @return uint32_t : bitmask for GPIO input pins, BIT(0) for GPIO0. + */ +uint32_t gpio_input_get(void); + +/** + * @brief Select pad as a gpio function from IOMUX. + * + * @param uint32_t gpio_num : gpio number, 0~15 + * + * @return None + */ +static inline void gpio_pad_select_gpio(uint32_t gpio_num) +{ + uint32_t gpio_mux_reg = PERIPHS_GPIO_MUX_REG(gpio_num); + + if (gpio_num == 0 || gpio_num == 2 || gpio_num == 4 || gpio_num == 5) { + PIN_FUNC_SELECT(gpio_mux_reg, 0); + } else { + PIN_FUNC_SELECT(gpio_mux_reg, 3); + } +} + +/** + * @brief Pull up the pad from gpio number. + * + * @param uint32_t gpio_num : gpio number, 0~15 + * + * @return None + */ +static inline void gpio_pad_pullup(uint32_t gpio_num) +{ + uint32_t gpio_mux_reg = PERIPHS_GPIO_MUX_REG(gpio_num); + + PIN_PULLUP_EN(gpio_mux_reg); +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ROM_GPIO_H_ */