start application if valid at boot

if the application is not valid, check and start the bootloader

Change-Id: I323f2b3a1828d3e40a02c7fc755d07009fb43a85
This commit is contained in:
Kevin Redon 2019-01-09 18:01:13 +01:00
parent b0a7dde6a6
commit 388dac3f87
2 changed files with 85 additions and 42 deletions

View File

@ -1,45 +1,95 @@
/**
* \file
* \brief USB DFU bootloader implementation (DFU mode)
*
* \brief Application implement
* Copyright (c) 2018-2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries.
* Copyright (c) 2018 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* \asf_license_start
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* \page License
*
* Subject to your compliance with these terms, you may use Microchip
* software and any derivatives exclusively with Microchip products.
* It is your responsibility to comply with third party license terms applicable
* to your use of third party software (including open source software) that
* may accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "atmel_start.h"
#include "atmel_start_pins.h"
/** Start address of the application in flash
* \remark must be initialized by check_bootloader
*/
static uint32_t* application_start_address;
/** Check if the bootloader is valid
* \return true if the bootloader is valid and can be run
* \remark initializes application_start_address
*/
static bool check_bootloader(void)
{
if (hri_nvmctrl_read_STATUS_BOOTPROT_bf(FLASH_0.dev.hw) > 15) { // ensure BOOTPROT setting is valid
return false;
}
application_start_address = (uint32_t*)((15 - hri_nvmctrl_read_STATUS_BOOTPROT_bf(FLASH_0.dev.hw)) * 8192); // calculate bootloader size to know start address of the application (e.g. after the bootloader)
if (0 == application_start_address) { // no space has been reserved for the bootloader
return false;
}
return true;
}
/** Check if starting the bootloader is forced
* \return true of the DFU bootloader should be started
*/
static bool check_force_dfu(void)
{
}
/** Check if the application is valid
* \return true if the application is valid and can be started
* \warning application_start_address must be initialized
*/
static bool check_application(void)
{
/* the application starts with the vector table
* the first entry in the vector table is the initial stack pointer (SP) address
* the stack will be placed in RAM which begins at 0x2000 0000, and there is up to 256 KB of RAM (0x40000).
* if the SP is not in this range (e.g. flash has been erased) there is no valid application
* the second entry in the vector table is the reset address, corresponding to the application start
*/
return (0x20000000 == ((*application_start_address) & 0xFFF80000));
}
/** Start the application
* \warning application_start_address must be initialized
*/
static void start_application(void)
{
__set_MSP(*application_start_address); // re-base the Stack Pointer
SCB->VTOR = ((uint32_t) application_start_address & SCB_VTOR_TBLOFF_Msk); // re-base the vector table base address
asm("bx %0"::"r"(*(application_start_address + 1))); // jump to application Reset Handler in the application */
}
int main(void)
{
atmel_start_init();
usb_dfu();
atmel_start_init(); // initialise system
if (!check_bootloader()) { // check bootloader
// blink the LED to tell the user we don't know where the application starts
while (true) {
gpio_set_pin_level(LED_SYSTEM, false);
delay_ms(500);
gpio_set_pin_level(LED_SYSTEM, true);
delay_ms(500);
}
}
if (check_application()) { // application is valid
start_application(); // start application
} else {
usb_dfu(); // start DFU bootloader
}
}

View File

@ -82,23 +82,16 @@ void usb_dfu(void)
while (!dfudf_is_enabled()); // wait for DFU to be installed
gpio_set_pin_level(LED_SYSTEM, false); // switch LED on to indicate USB DFU stack is ready
uint32_t application_start = hri_nvmctrl_read_STATUS_BOOTPROT_bf(FLASH_0.dev.hw); // read BOOTPROT setting to get the bootloader size
ASSERT(application_start <= 15);
application_start = (15 - application_start) * 8192; // calculate bootloader size to know where we should write the application firmware
while (0 == application_start) { // no space has been reserved for the bootloader
// blink the LED to tell the user we don't know where the application starts
gpio_set_pin_level(LED_SYSTEM, false);
delay_ms(500);
gpio_set_pin_level(LED_SYSTEM, true);
delay_ms(500);
}
ASSERT(hri_nvmctrl_read_STATUS_BOOTPROT_bf(FLASH_0.dev.hw) <= 15);
uint32_t application_start_address = (15 - hri_nvmctrl_read_STATUS_BOOTPROT_bf(FLASH_0.dev.hw)) * 8192; // calculate bootloader size to know where we should write the application firmware
ASSERT(application_start_address > 0);
while (true) { // main DFU infinite loop
// run the second part of the USB DFU state machine handling non-USB aspects
if (USB_DFU_STATE_DFU_DNLOAD_SYNC == dfu_state || USB_DFU_STATE_DFU_DNBUSY == dfu_state) { // there is some data to be flashed
gpio_set_pin_level(LED_SYSTEM, true); // switch LED off to indicate we are flashing
if (dfu_download_length > 0) { // there is some data to be flashed
int32_t rc = flash_write(&FLASH_0, application_start + dfu_download_offset, dfu_download_data, dfu_download_length); // write downloaded data chunk to flash
int32_t rc = flash_write(&FLASH_0, application_start_address + dfu_download_offset, dfu_download_data, dfu_download_length); // write downloaded data chunk to flash
if (ERR_NONE == rc) {
dfu_state = USB_DFU_STATE_DFU_DNLOAD_IDLE; // indicate flashing this block has been completed
} else { // there has been a programming error