feat(bootloader): Support to trigger test app in bootloader

This commit is contained in:
Dong Heng
2018-12-26 10:45:04 +08:00
committed by Wu Jian Gang
parent a61f19859a
commit e124146e2b
6 changed files with 178 additions and 7 deletions

View File

@ -126,24 +126,33 @@ config BOOTLOADER_DATA_FACTORY_RESET
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)"

View File

@ -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.

View File

@ -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 );

View File

@ -165,11 +165,23 @@ bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_dat
#include <stdbool.h>
#include <stdint.h>
#include <xtensa/hal.h>
#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

View File

@ -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_

View File

@ -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 <stdint.h>
#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_ */