aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKévin Redon <kredon@sysmocom.de>2019-01-09 18:01:13 +0100
committerKévin Redon <kredon@sysmocom.de>2019-01-16 18:41:23 +0100
commit388dac3f877e7e6f6ce9db541567a9bc05f3a15e (patch)
tree5c45937d875aaef6c16e0d777030682278dfff88
parentb0a7dde6a673e21189761c3134b6326474746968 (diff)
start application if valid at boot
if the application is not valid, check and start the bootloader Change-Id: I323f2b3a1828d3e40a02c7fc755d07009fb43a85
-rw-r--r--usb_dfu_main.c112
-rw-r--r--usb_start.c15
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 <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
+ }
}
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