From 388dac3f877e7e6f6ce9db541567a9bc05f3a15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Redon?= Date: Wed, 9 Jan 2019 18:01:13 +0100 Subject: start application if valid at boot if the application is not valid, check and start the bootloader Change-Id: I323f2b3a1828d3e40a02c7fc755d07009fb43a85 --- usb_dfu_main.c | 112 +++++++++++++++++++++++++++++++++++++++++---------------- usb_start.c | 15 +++----- 2 files changed, 85 insertions(+), 42 deletions(-) diff --git a/usb_dfu_main.c b/usb_dfu_main.c index 2535475..91748a5 100644 --- a/usb_dfu_main.c +++ b/usb_dfu_main.c @@ -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 * - * Copyright (c) 2015-2018 Microchip Technology Inc. and its subsidiaries. - * Copyright (c) 2018 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon + * 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 Microchip Support + * 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 + } } diff --git a/usb_start.c b/usb_start.c index 7503094..ad91840 100644 --- a/usb_start.c +++ b/usb_start.c @@ -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 -- cgit v1.2.3