From 522ed2d99ba4b0ed6f749a6c2218a6d4ec0c9bef Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Tue, 29 Oct 2019 14:40:51 -0700 Subject: [PATCH] NuttX based PX4 bootloader stm32h7 booloader:Obey VBUS input stm32h7 booloader:Fully deinit systic --- cmake/px4_add_common_flags.cmake | 3 + platforms/nuttx/CMakeLists.txt | 15 +- platforms/nuttx/src/bootloader/CMakeLists.txt | 40 + platforms/nuttx/src/bootloader/bl.c | 1013 +++++++++++++++++ platforms/nuttx/src/bootloader/bl.h | 130 +++ platforms/nuttx/src/bootloader/cdcacm.h | 46 + .../nuttx/src/bootloader/lib/CMakeLists.txt | 41 + platforms/nuttx/src/bootloader/lib/cdcacm.c | 138 +++ .../nuttx/src/bootloader/lib/flash_cache.c | 159 +++ .../nuttx/src/bootloader/lib/flash_cache.h | 69 ++ platforms/nuttx/src/bootloader/lib/systick.c | 76 ++ platforms/nuttx/src/bootloader/lib/systick.h | 44 + platforms/nuttx/src/bootloader/lib/uart.c | 130 +++ platforms/nuttx/src/bootloader/stm32h7/main.c | 802 +++++++++++++ platforms/nuttx/src/bootloader/uart.h | 45 + 15 files changed, 2750 insertions(+), 1 deletion(-) create mode 100644 platforms/nuttx/src/bootloader/CMakeLists.txt create mode 100644 platforms/nuttx/src/bootloader/bl.c create mode 100644 platforms/nuttx/src/bootloader/bl.h create mode 100644 platforms/nuttx/src/bootloader/cdcacm.h create mode 100644 platforms/nuttx/src/bootloader/lib/CMakeLists.txt create mode 100644 platforms/nuttx/src/bootloader/lib/cdcacm.c create mode 100644 platforms/nuttx/src/bootloader/lib/flash_cache.c create mode 100644 platforms/nuttx/src/bootloader/lib/flash_cache.h create mode 100644 platforms/nuttx/src/bootloader/lib/systick.c create mode 100644 platforms/nuttx/src/bootloader/lib/systick.h create mode 100644 platforms/nuttx/src/bootloader/lib/uart.c create mode 100644 platforms/nuttx/src/bootloader/stm32h7/main.c create mode 100644 platforms/nuttx/src/bootloader/uart.h diff --git a/cmake/px4_add_common_flags.cmake b/cmake/px4_add_common_flags.cmake index 7fec45a770..dfc405ee02 100644 --- a/cmake/px4_add_common_flags.cmake +++ b/cmake/px4_add_common_flags.cmake @@ -171,6 +171,9 @@ function(px4_add_common_flags) ${PX4_BINARY_DIR} ${PX4_BINARY_DIR}/src/lib +if("${PX4_BOARD_LABEL}" STREQUAL "bootloader") + ${PX4_SOURCE_DIR}/platforms/${PX4_PLATFORM}/src/bootloader +endif() ${PX4_SOURCE_DIR}/platforms/${PX4_PLATFORM}/src/px4/${PX4_CHIP_MANUFACTURER}/${PX4_CHIP}/include ${PX4_SOURCE_DIR}/platforms/${PX4_PLATFORM}/src/px4/common/include ${PX4_SOURCE_DIR}/platforms/common/include diff --git a/platforms/nuttx/CMakeLists.txt b/platforms/nuttx/CMakeLists.txt index 13f6801b51..4c195db0b7 100644 --- a/platforms/nuttx/CMakeLists.txt +++ b/platforms/nuttx/CMakeLists.txt @@ -47,6 +47,16 @@ get_property(module_libraries GLOBAL PROPERTY PX4_MODULE_LIBRARIES) add_subdirectory(NuttX ${PX4_BINARY_DIR}/NuttX) set(nuttx_libs) +if("${PX4_BOARD_LABEL}" STREQUAL "bootloader") + set(SCRIPT_PREFIX ${PX4_BOARD_LABEL}_) + add_subdirectory(src/bootloader) + list(APPEND nuttx_libs + bootloader + bootloader_lib + drivers_board + ) +endif() + list(APPEND nuttx_libs nuttx_apps nuttx_arch @@ -94,7 +104,7 @@ target_link_libraries(px4 PRIVATE -fno-exceptions -fno-rtti - -Wl,--script=${PX4_BINARY_DIR_CYG}/NuttX/nuttx-config/scripts/script.ld + -Wl,--script=${PX4_BINARY_DIR_CYG}/NuttX/nuttx-config/scripts/${SCRIPT_PREFIX}script.ld -Wl,-Map=${PX4_CONFIG}.map -Wl,--warn-common -Wl,--gc-sections @@ -205,6 +215,9 @@ if(NOT PX4_BUILD MATCHES "px4_io-v2") elseif(CONFIG_ARCH_CHIP_STM32F777NI) set(DEBUG_DEVICE "STM32F777NI") set(DEBUG_SVD_FILE "STM32F7x7.svd") + elseif(CONFIG_ARCH_CHIP_STM32H743ZI) + set(DEBUG_DEVICE "STM32H743ZI") + set(DEBUG_SVD_FILE "STM32H7x3.svd") endif() file(GLOB_RECURSE DEBUG_SVD_FILE_PATH ${CMAKE_SOURCE_DIR}/../cmsis-svd/*/${DEBUG_SVD_FILE}) diff --git a/platforms/nuttx/src/bootloader/CMakeLists.txt b/platforms/nuttx/src/bootloader/CMakeLists.txt new file mode 100644 index 0000000000..b2ecb328c5 --- /dev/null +++ b/platforms/nuttx/src/bootloader/CMakeLists.txt @@ -0,0 +1,40 @@ +############################################################################ +# +# Copyright (c) 2019 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +add_library(bootloader + bl.c + ${PX4_CHIP}/main.c +) + +add_subdirectory(lib) +add_dependencies(bootloader prebuild_targets) \ No newline at end of file diff --git a/platforms/nuttx/src/bootloader/bl.c b/platforms/nuttx/src/bootloader/bl.c new file mode 100644 index 0000000000..d48df0d1fb --- /dev/null +++ b/platforms/nuttx/src/bootloader/bl.c @@ -0,0 +1,1013 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2014 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file bl.c + * + * Common bootloader logic. + * + * Aside from the header includes below, this file should have no board-specific logic. + */ +#include "hw_config.h" +#include +#include +#include + +#include "bl.h" +#include "cdcacm.h" +#include "uart.h" + +// bootloader flash update protocol. +// +// Command format: +// +// [] +// +// Reply format: +// +// [] +// +// The and values come from the PROTO_ defines below, +// the <*_data> fields is described only for opcodes that transfer data; +// in all other cases the field is omitted. +// +// Expected workflow (protocol 3) is: +// +// GET_SYNC verify that the board is present +// GET_DEVICE determine which board (select firmware to upload) +// CHIP_ERASE erase the program area and reset address counter +// loop: +// PROG_MULTI program bytes +// GET_CRC verify CRC of entire flashable area +// RESET finalise flash programming, reset chip and starts application +// + +#define BL_PROTOCOL_VERSION 5 // The revision of the bootloader protocol +//* Next revision needs to update + +// protocol bytes +#define PROTO_INSYNC 0x12 // 'in sync' byte sent before status +#define PROTO_EOC 0x20 // end of command + +// Reply bytes +#define PROTO_OK 0x10 // INSYNC/OK - 'ok' response +#define PROTO_FAILED 0x11 // INSYNC/FAILED - 'fail' response +#define PROTO_INVALID 0x13 // INSYNC/INVALID - 'invalid' response for bad commands +#define PROTO_BAD_SILICON_REV 0x14 // On the F4 series there is an issue with < Rev 3 silicon +#define PROTO_RESERVED_0X15 0x15 // Reserved + +// see https://pixhawk.org/help/errata +// Command bytes +#define PROTO_GET_SYNC 0x21 // NOP for re-establishing sync +#define PROTO_GET_DEVICE 0x22 // get device ID bytes +#define PROTO_CHIP_ERASE 0x23 // erase program area and reset program address +#define PROTO_PROG_MULTI 0x27 // write bytes at program address and increment +#define PROTO_GET_CRC 0x29 // compute & return a CRC +#define PROTO_GET_OTP 0x2a // read a byte from OTP at the given address +#define PROTO_GET_SN 0x2b // read a word from UDID area ( Serial) at the given address +#define PROTO_GET_CHIP 0x2c // read chip version (MCU IDCODE) +#define PROTO_SET_DELAY 0x2d // set minimum boot delay +#define PROTO_GET_CHIP_DES 0x2e // read chip version In ASCII +#define PROTO_BOOT 0x30 // boot the application +#define PROTO_DEBUG 0x31 // emit debug information - format not defined +#define PROTO_SET_BAUD 0x33 // set baud rate on uart + +#define PROTO_RESERVED_0X36 0x36 // Reserved +#define PROTO_RESERVED_0X37 0x37 // Reserved +#define PROTO_RESERVED_0X38 0x38 // Reserved +#define PROTO_RESERVED_0X39 0x39 // Reserved + +#define PROTO_PROG_MULTI_MAX 64 // maximum PROG_MULTI size +#define PROTO_READ_MULTI_MAX 255 // size of the size field + +/* argument values for PROTO_GET_DEVICE */ +#define PROTO_DEVICE_BL_REV 1 // bootloader revision +#define PROTO_DEVICE_BOARD_ID 2 // board ID +#define PROTO_DEVICE_BOARD_REV 3 // board revision +#define PROTO_DEVICE_FW_SIZE 4 // size of flashable area +#define PROTO_DEVICE_VEC_AREA 5 // contents of reserved vectors 7-10 + +#define STATE_PROTO_OK 0x10 // INSYNC/OK - 'ok' response +#define STATE_PROTO_FAILED 0x11 // INSYNC/FAILED - 'fail' response +#define STATE_PROTO_INVALID 0x13 // INSYNC/INVALID - 'invalid' response for bad commands +#define STATE_PROTO_BAD_SILICON_REV 0x14 // On the F4 series there is an issue with < Rev 3 silicon +#define STATE_PROTO_RESERVED_0X15 0x15 // Reserved + + +// State +#define STATE_PROTO_GET_SYNC 0x1 // Have Seen NOP for re-establishing sync +#define STATE_PROTO_GET_DEVICE 0x2 // Have Seen get device ID bytes +#define STATE_PROTO_CHIP_ERASE 0x4 // Have Seen erase program area and reset program address +#define STATE_PROTO_PROG_MULTI 0x8 // Have Seen write bytes at program address and increment +#define STATE_PROTO_GET_CRC 0x10 // Have Seen compute & return a CRC +#define STATE_PROTO_GET_OTP 0x20 // Have Seen read a byte from OTP at the given address +#define STATE_PROTO_GET_SN 0x40 // Have Seen read a word from UDID area ( Serial) at the given address +#define STATE_PROTO_GET_CHIP 0x80 // Have Seen read chip version (MCU IDCODE) +#define STATE_PROTO_GET_CHIP_DES 0x100 // Have Seen read chip version In ASCII +#define STATE_PROTO_BOOT 0x200 // Have Seen boot the application + +#if defined(TARGET_HW_PX4_PIO_V1) +#define STATE_ALLOWS_ERASE (STATE_PROTO_GET_SYNC) +#define STATE_ALLOWS_REBOOT (STATE_PROTO_GET_SYNC) +# define SET_BL_STATE(s) +#else +#define STATE_ALLOWS_ERASE (STATE_PROTO_GET_SYNC|STATE_PROTO_GET_DEVICE|STATE_PROTO_GET_CHIP) +#define STATE_ALLOWS_REBOOT (STATE_ALLOWS_ERASE|STATE_PROTO_PROG_MULTI|STATE_PROTO_GET_CRC) +# define SET_BL_STATE(s) bl_state |= (s) +#endif + +static uint8_t bl_type; +static uint8_t last_input; + +inline void cinit(void *config, uint8_t interface) +{ +#if INTERFACE_USB + + if (interface == USB) { + return usb_cinit(config); + } + +#endif +#if INTERFACE_USART + + if (interface == USART) { + return uart_cinit(config); + } + +#endif +} +inline void cfini(void) +{ +#if INTERFACE_USB + usb_cfini(); +#endif +#if INTERFACE_USART + uart_cfini(); +#endif +} +inline int cin(uint32_t devices) +{ +#if INTERFACE_USB + + if ((bl_type == NONE || bl_type == USB) && (devices & USB0_DEV) != 0) { + int usb_in = usb_cin(); + + if (usb_in >= 0) { + last_input = USB; + return usb_in; + } + } + +#endif + +#if INTERFACE_USART + + if ((bl_type == NONE || bl_type == USART) && (devices & SERIAL0_DEV) != 0) { + int uart_in = uart_cin(); + + if (uart_in >= 0) { + last_input = USART; + return uart_in; + } + } + +#endif + + return -1; +} + +inline void cout(uint8_t *buf, unsigned len) +{ +#if INTERFACE_USB + + if (bl_type == USB) { + usb_cout(buf, len); + } + +#endif +#if INTERFACE_USART + + if (bl_type == USART) { + uart_cout(buf, len); + } + +#endif +} + +/* The PX4IO is so low on FLASH that this abstaction is not possible as + * a called API. Therefore these macros are needed. + */ +#if defined(TARGET_HW_PX4_PIO_V1) +# include +#include +#include + +#define arch_systic_init(d) \ + systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); \ + systick_set_reload(board_info.systick_mhz * 1000); \ + systick_interrupt_enable(); \ + systick_counter_enable(); + +#define arch_systic_deinit() \ + systick_interrupt_disable(); \ + systick_counter_disable(); + +#define arch_flash_lock flash_lock +#define arch_flash_unlock flash_unlock + +#define arch_setvtor(address) SCB_VTOR = address; + +#endif + +static const uint32_t bl_proto_rev = BL_PROTOCOL_VERSION; // value returned by PROTO_DEVICE_BL_REV + +static unsigned head, tail; +static uint8_t rx_buf[256] USB_DATA_ALIGN; + +static enum led_state {LED_BLINK, LED_ON, LED_OFF} _led_state; + +void sys_tick_handler(void); + +void +buf_put(uint8_t b) +{ + unsigned next = (head + 1) % sizeof(rx_buf); + + if (next != tail) { + rx_buf[head] = b; + head = next; + } +} + +int +buf_get(void) +{ + int ret = -1; + + if (tail != head) { + ret = rx_buf[tail]; + tail = (tail + 1) % sizeof(rx_buf); + } + + return ret; +} + +static void +do_jump(uint32_t stacktop, uint32_t entrypoint) +{ + asm volatile( + "msr msp, %0 \n" + "bx %1 \n" + : : "r"(stacktop), "r"(entrypoint) :); + + // just to keep noreturn happy + for (;;) ; +} + +void +jump_to_app() +{ + const uint32_t *app_base = (const uint32_t *)APP_LOAD_ADDRESS; + + /* + * We refuse to program the first word of the app until the upload is marked + * complete by the host. So if it's not 0xffffffff, we should try booting it. + */ + if (app_base[0] == 0xffffffff) { + return; + } + + /* + * The second word of the app is the entrypoint; it must point within the + * flash area (or we have a bad flash). + */ + if (app_base[1] < APP_LOAD_ADDRESS) { + return; + } + + if (app_base[1] >= (APP_LOAD_ADDRESS + board_info.fw_size)) { + return; + } + + /* just for paranoia's sake */ + arch_flash_lock(); + + /* kill the systick interrupt */ + arch_systic_deinit(); + + /* deinitialise the interface */ + cfini(); + + /* reset the clock */ + clock_deinit(); + + /* deinitialise the board */ + board_deinit(); + + /* switch exception handlers to the application */ + arch_setvtor(APP_LOAD_ADDRESS); + + /* extract the stack and entrypoint from the app vector table and go */ + do_jump(app_base[0], app_base[1]); +} + +volatile unsigned timer[NTIMERS]; + +void +sys_tick_handler(void) +{ + unsigned i; + + for (i = 0; i < NTIMERS; i++) + if (timer[i] > 0) { + timer[i]--; + } + + if ((_led_state == LED_BLINK) && (timer[TIMER_LED] == 0)) { + led_toggle(LED_BOOTLOADER); + timer[TIMER_LED] = 50; + } +} + +void +delay(unsigned msec) +{ + timer[TIMER_DELAY] = msec; + + while (timer[TIMER_DELAY] > 0) + ; +} + +static void +led_set(enum led_state state) +{ + _led_state = state; + + switch (state) { + case LED_OFF: + led_off(LED_BOOTLOADER); + break; + + case LED_ON: + led_on(LED_BOOTLOADER); + break; + + case LED_BLINK: + /* restart the blink state machine ASAP */ + timer[TIMER_LED] = 0; + break; + } +} + +static void +sync_response(void) +{ + uint8_t data[] = { + PROTO_INSYNC, // "in sync" + PROTO_OK // "OK" + }; + + cout(data, sizeof(data)); +} + +#if defined(TARGET_HW_PX4_FMU_V4) +static void +bad_silicon_response(void) +{ + uint8_t data[] = { + PROTO_INSYNC, // "in sync" + PROTO_BAD_SILICON_REV // "issue with < Rev 3 silicon" + }; + + cout(data, sizeof(data)); +} +#endif + +static void +invalid_response(void) +{ + uint8_t data[] = { + PROTO_INSYNC, // "in sync" + PROTO_INVALID // "invalid command" + }; + + cout(data, sizeof(data)); +} + +static void +failure_response(void) +{ + uint8_t data[] = { + PROTO_INSYNC, // "in sync" + PROTO_FAILED // "command failed" + }; + + cout(data, sizeof(data)); +} + +static volatile unsigned cin_count; + +static int +cin_wait(unsigned timeout) +{ + int c = -1; + + /* start the timeout */ + timer[TIMER_CIN] = timeout; + + do { + c = cin(board_get_devices()); + + if (c >= 0) { + cin_count++; + break; + } + + } while (timer[TIMER_CIN] > 0); + + return c; +} + +/** + * Function to wait for EOC + * + * @param timeout length of time in ms to wait for the EOC to be received + * @return true if the EOC is returned within the timeout perio, else false + */ +inline static bool +wait_for_eoc(unsigned timeout) +{ + return cin_wait(timeout) == PROTO_EOC; +} + +static void +cout_word(uint32_t val) +{ + cout((uint8_t *)&val, 4); +} + +static int +cin_word(uint32_t *wp, unsigned timeout) +{ + union { + uint32_t w; + uint8_t b[4]; + } u; + + for (unsigned i = 0; i < 4; i++) { + int c = cin_wait(timeout); + + if (c < 0) { + return c; + } + + u.b[i] = c & 0xff; + } + + *wp = u.w; + return 0; +} + +static uint32_t +crc32(const uint8_t *src, unsigned len, unsigned state) +{ + static uint32_t crctab[256]; + + /* check whether we have generated the CRC table yet */ + /* this is much smaller than a static table */ + if (crctab[1] == 0) { + for (unsigned i = 0; i < 256; i++) { + uint32_t c = i; + + for (unsigned j = 0; j < 8; j++) { + if (c & 1) { + c = 0xedb88320U ^ (c >> 1); + + } else { + c = c >> 1; + } + } + + crctab[i] = c; + } + } + + for (unsigned i = 0; i < len; i++) { + state = crctab[(state ^ src[i]) & 0xff] ^ (state >> 8); + } + + return state; +} + +void +bootloader(unsigned timeout) +{ + bl_type = NONE; // The type of the bootloader, whether loading from USB or USART, will be determined by on what port the bootloader recevies its first valid command. + volatile uint32_t bl_state = 0; // Must see correct command sequence to erase and reboot (commit first word) + uint32_t address = board_info.fw_size; /* force erase before upload will work */ + uint32_t first_word = 0xffffffff; + + /* (re)start the timer system */ + arch_systic_init(); + + /* if we are working with a timeout, start it running */ + if (timeout) { + timer[TIMER_BL_WAIT] = timeout; + } + + /* make the LED blink while we are idle */ + led_set(LED_BLINK); + + while (true) { + volatile int c; + int arg; + static union { + uint8_t c[256]; + uint32_t w[64]; + } flash_buffer; + + // Wait for a command byte + led_off(LED_ACTIVITY); + + do { + /* if we have a timeout and the timer has expired, return now */ + if (timeout && !timer[TIMER_BL_WAIT]) { + return; + } + + /* try to get a byte from the host */ + c = cin_wait(0); + + } while (c < 0); + + led_on(LED_ACTIVITY); + + // handle the command byte + switch (c) { + + // sync + // + // command: GET_SYNC/EOC + // reply: INSYNC/OK + // + case PROTO_GET_SYNC: + + /* expect EOC */ + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + bl_state = STATE_PROTO_GET_SYNC; + break; + + // get device info + // + // command: GET_DEVICE//EOC + // BL_REV reply: /INSYNC/EOC + // BOARD_ID reply: /INSYNC/EOC + // BOARD_REV reply: /INSYNC/EOC + // FW_SIZE reply: /INSYNC/EOC + // VEC_AREA reply /INSYNC/EOC + // bad arg reply: INSYNC/INVALID + // + case PROTO_GET_DEVICE: + /* expect arg then EOC */ + arg = cin_wait(1000); + + if (arg < 0) { + goto cmd_bad; + } + + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + switch (arg) { + case PROTO_DEVICE_BL_REV: + cout((uint8_t *)&bl_proto_rev, sizeof(bl_proto_rev)); + break; + + case PROTO_DEVICE_BOARD_ID: + cout((uint8_t *)&board_info.board_type, sizeof(board_info.board_type)); + break; + + case PROTO_DEVICE_BOARD_REV: + cout((uint8_t *)&board_info.board_rev, sizeof(board_info.board_rev)); + break; + + case PROTO_DEVICE_FW_SIZE: + cout((uint8_t *)&board_info.fw_size, sizeof(board_info.fw_size)); + break; + + case PROTO_DEVICE_VEC_AREA: + for (unsigned p = 7; p <= 10; p++) { + uint32_t bytes = flash_func_read_word(p * 4); + + cout((uint8_t *)&bytes, sizeof(bytes)); + } + + break; + + default: + goto cmd_bad; + } + + SET_BL_STATE(STATE_PROTO_GET_DEVICE); + break; + + // erase and prepare for programming + // + // command: ERASE/EOC + // success reply: INSYNC/OK + // erase failure: INSYNC/FAILURE + // + case PROTO_CHIP_ERASE: + + /* expect EOC */ + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + +#if defined(TARGET_HW_PX4_FMU_V4) + + if (check_silicon()) { + goto bad_silicon; + } + +#endif + + if ((bl_state & STATE_ALLOWS_ERASE) != STATE_ALLOWS_ERASE) { + goto cmd_bad; + } + + // clear the bootloader LED while erasing - it stops blinking at random + // and that's confusing + led_set(LED_ON); + + // erase all sectors + arch_flash_unlock(); + + for (int i = 0; flash_func_sector_size(i) != 0; i++) { + flash_func_erase_sector(i); + } + + // disable the LED while verifying the erase + led_set(LED_OFF); + + // verify the erase + for (address = 0; address < board_info.fw_size; address += 4) + if (flash_func_read_word(address) != 0xffffffff) { + goto cmd_fail; + } + + address = 0; + SET_BL_STATE(STATE_PROTO_CHIP_ERASE); + + // resume blinking + led_set(LED_BLINK); + break; + + // program bytes at current address + // + // command: PROG_MULTI///EOC + // success reply: INSYNC/OK + // invalid reply: INSYNC/INVALID + // readback failure: INSYNC/FAILURE + // + case PROTO_PROG_MULTI: // program bytes + // expect count + arg = cin_wait(50); + + if (arg < 0) { + goto cmd_bad; + } + + // sanity-check arguments + if (arg % 4) { + goto cmd_bad; + } + + if ((address + arg) > board_info.fw_size) { + goto cmd_bad; + } + + if ((unsigned int)arg > sizeof(flash_buffer.c)) { + goto cmd_bad; + } + + for (int i = 0; i < arg; i++) { + c = cin_wait(1000); + + if (c < 0) { + goto cmd_bad; + } + + flash_buffer.c[i] = c; + } + + if (!wait_for_eoc(200)) { + goto cmd_bad; + } + + if (address == 0) { + +#if defined(TARGET_HW_PX4_FMU_V4) + + if (check_silicon()) { + goto bad_silicon; + } + +#endif + + // save the first word and don't program it until everything else is done + first_word = flash_buffer.w[0]; + // replace first word with bits we can overwrite later + flash_buffer.w[0] = 0xffffffff; + } + + arg /= 4; + + for (int i = 0; i < arg; i++) { + + // program the word + flash_func_write_word(address, flash_buffer.w[i]); + + // do immediate read-back verify + if (flash_func_read_word(address) != flash_buffer.w[i]) { + goto cmd_fail; + } + + address += 4; + } + + SET_BL_STATE(STATE_PROTO_PROG_MULTI); + + break; + + // fetch CRC of the entire flash area + // + // command: GET_CRC/EOC + // reply: /INSYNC/OK + // + case PROTO_GET_CRC: + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + // compute CRC of the programmed area + uint32_t sum = 0; + + for (unsigned p = 0; p < board_info.fw_size; p += 4) { + uint32_t bytes; + + if ((p == 0) && (first_word != 0xffffffff)) { + bytes = first_word; + + } else { + bytes = flash_func_read_word(p); + } + + sum = crc32((uint8_t *)&bytes, sizeof(bytes), sum); + } + + cout_word(sum); + SET_BL_STATE(STATE_PROTO_GET_CRC); + break; + + // read a word from the OTP + // + // command: GET_OTP//EOC + // reply: /INSYNC/OK + case PROTO_GET_OTP: + // expect argument + { + uint32_t index = 0; + + if (cin_word(&index, 100)) { + goto cmd_bad; + } + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + cout_word(flash_func_read_otp(index)); + } + break; + + // read the SN from the UDID + // + // command: GET_SN//EOC + // reply: /INSYNC/OK + case PROTO_GET_SN: + // expect argument + { + uint32_t index = 0; + + if (cin_word(&index, 100)) { + goto cmd_bad; + } + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + // expect valid indices 0, 4 ...ARCH_SN_MAX_LENGTH-4 + + if (index % sizeof(uint32_t) != 0 || index > ARCH_SN_MAX_LENGTH - sizeof(uint32_t)) { + goto cmd_bad; + } + + cout_word(flash_func_read_sn(index)); + } + + SET_BL_STATE(STATE_PROTO_GET_SN); + break; + + // read the chip ID code + // + // command: GET_CHIP/EOC + // reply: /INSYNC/OK + case PROTO_GET_CHIP: { + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + cout_word(get_mcu_id()); + SET_BL_STATE(STATE_PROTO_GET_CHIP); + } + break; + + // read the chip description + // + // command: GET_CHIP_DES/EOC + // reply: /INSYNC/OK + case PROTO_GET_CHIP_DES: { + uint8_t buffer[MAX_DES_LENGTH]; + unsigned len = MAX_DES_LENGTH; + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + len = get_mcu_desc(len, buffer); + cout_word(len); + cout(buffer, len); + SET_BL_STATE(STATE_PROTO_GET_CHIP_DES); + } + break; + +#ifdef BOOT_DELAY_ADDRESS + + case PROTO_SET_DELAY: { + /* + Allow for the bootloader to setup a + boot delay signature which tells the + board to delay for at least a + specified number of seconds on boot. + */ + int v = cin_wait(100); + + if (v < 0) { + goto cmd_bad; + } + + uint8_t boot_delay = v & 0xFF; + + if (boot_delay > BOOT_DELAY_MAX) { + goto cmd_bad; + } + + // expect EOC + if (!wait_for_eoc(2)) { + goto cmd_bad; + } + + uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS); + uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4); + + if (sig1 != BOOT_DELAY_SIGNATURE1 || + sig2 != BOOT_DELAY_SIGNATURE2) { + goto cmd_bad; + } + + uint32_t value = (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00) | boot_delay; + flash_func_write_word(BOOT_DELAY_ADDRESS, value); + + if (flash_func_read_word(BOOT_DELAY_ADDRESS) != value) { + goto cmd_fail; + } + } + break; +#endif + + // finalise programming and boot the system + // + // command: BOOT/EOC + // reply: INSYNC/OK + // + case PROTO_BOOT: + + // expect EOC + if (!wait_for_eoc(1000)) { + goto cmd_bad; + } + + if (first_word != 0xffffffff && (bl_state & STATE_ALLOWS_REBOOT) != STATE_ALLOWS_REBOOT) { + goto cmd_bad; + } + + // program the deferred first word + if (first_word != 0xffffffff) { + flash_func_write_word(0, first_word); + + if (flash_func_read_word(0) != first_word) { + goto cmd_fail; + } + + // revert in case the flash was bad... + first_word = 0xffffffff; + } + + // send a sync and wait for it to be collected + sync_response(); + delay(100); + + // quiesce and jump to the app + return; + + case PROTO_DEBUG: + // XXX reserved for ad-hoc debugging as required + break; + + default: + continue; + } + + // we got a command worth syncing, so kill the timeout because + // we are probably talking to the uploader + timeout = 0; + + // Set the bootloader port based on the port from which we received the first valid command + if (bl_type == NONE) { + bl_type = last_input; + } + + // send the sync response for this command + sync_response(); + continue; +cmd_bad: + // send an 'invalid' response but don't kill the timeout - could be garbage + invalid_response(); + bl_state = 0; + continue; + +cmd_fail: + // send a 'command failed' response but don't kill the timeout - could be garbage + failure_response(); + continue; + +#if defined(TARGET_HW_PX4_FMU_V4) +bad_silicon: + // send the bad silicon response but don't kill the timeout - could be garbage + bad_silicon_response(); + continue; +#endif + } +} diff --git a/platforms/nuttx/src/bootloader/bl.h b/platforms/nuttx/src/bootloader/bl.h new file mode 100644 index 0000000000..7c63f73443 --- /dev/null +++ b/platforms/nuttx/src/bootloader/bl.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2014 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file bl.h + * + * Common bootloader definitions. + */ + +#pragma once + +/***************************************************************************** + * Generic bootloader functions. + */ + +/* enum for whether bootloading via USB or USART */ +enum { + NONE, + USART, + USB +}; + +/* board info forwarded from board-specific code to booloader */ +struct boardinfo { + uint32_t board_type; + uint32_t board_rev; + uint32_t fw_size; + uint32_t systick_mhz; /* systick input clock */ + +} __attribute__((packed)); + +extern struct boardinfo board_info; + +extern void jump_to_app(void); +extern void bootloader(unsigned timeout); +extern void delay(unsigned msec); + +#define BL_WAIT_MAGIC 0x19710317 /* magic number in PWR regs to wait in bootloader */ + +/* generic timers */ +#define NTIMERS 4 +#define TIMER_BL_WAIT 0 +#define TIMER_CIN 1 +#define TIMER_LED 2 +#define TIMER_DELAY 3 +extern volatile unsigned timer[NTIMERS]; /* each timer decrements every millisecond if > 0 */ + +/* generic receive buffer for async reads */ +extern void buf_put(uint8_t b); +extern int buf_get(void); + +/***************************************************************************** + * Chip/board functions. + */ + +/* LEDs */ +#define LED_ACTIVITY 1 +#define LED_BOOTLOADER 2 + +#ifdef BOOT_DELAY_ADDRESS +# define BOOT_DELAY_SIGNATURE1 0x92c2ecff +# define BOOT_DELAY_SIGNATURE2 0xc5057d5d +# define BOOT_DELAY_MAX 30 +#endif + +#define MAX_DES_LENGTH 20 + +#define arraySize(a) (sizeof((a))/sizeof(((a)[0]))) +extern void led_on(unsigned led); +extern void led_off(unsigned led); +extern void led_toggle(unsigned led); + +/* flash helpers from main_*.c */ +extern void board_deinit(void); +extern uint32_t board_get_devices(void); +extern void clock_deinit(void); +extern uint32_t flash_func_sector_size(unsigned sector); +extern void flash_func_erase_sector(unsigned sector); +extern void flash_func_write_word(uint32_t address, uint32_t word); +extern uint32_t flash_func_read_word(uint32_t address); +extern uint32_t flash_func_read_otp(uint32_t address); +extern uint32_t flash_func_read_sn(uint32_t address); +extern void arch_flash_lock(void); +extern void arch_flash_unlock(void); +extern void arch_setvtor(uint32_t address); +void arch_systic_init(void); +void arch_systic_deinit(void); + +extern uint32_t get_mcu_id(void); +int get_mcu_desc(int max, uint8_t *revstr); +extern int check_silicon(void); + +/***************************************************************************** + * Interface in/output. + */ + +extern void cinit(void *config, uint8_t interface); +extern void cfini(void); +extern int cin(uint32_t devices); +extern void cout(uint8_t *buf, unsigned len); diff --git a/platforms/nuttx/src/bootloader/cdcacm.h b/platforms/nuttx/src/bootloader/cdcacm.h new file mode 100644 index 0000000000..18175b5c68 --- /dev/null +++ b/platforms/nuttx/src/bootloader/cdcacm.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2014 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file cdcacm.h + * + * cdcacm bootloader definitions. + */ + +#pragma once + + +extern void usb_cinit(void *config); +extern void usb_cfini(void); +extern int usb_cin(void); +extern void usb_cout(uint8_t *buf, unsigned len); diff --git a/platforms/nuttx/src/bootloader/lib/CMakeLists.txt b/platforms/nuttx/src/bootloader/lib/CMakeLists.txt new file mode 100644 index 0000000000..3fbd03d7c1 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/CMakeLists.txt @@ -0,0 +1,41 @@ +############################################################################ +# +# Copyright (c) 2019 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +add_library(bootloader_lib + systick.c + cdcacm.c + uart.c + flash_cache.c +) + +add_dependencies(bootloader_lib prebuild_targets) \ No newline at end of file diff --git a/platforms/nuttx/src/bootloader/lib/cdcacm.c b/platforms/nuttx/src/bootloader/lib/cdcacm.c new file mode 100644 index 0000000000..3e1ded7717 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/cdcacm.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * + * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include "cdcacm.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "cdcacm.h" + +//#define SERIAL_TRACE + +int g_usb_df = -1; +char *g_device = 0; +char *g_init = 0; + +#if defined(SERIAL_TRACE) +int in = 0; +int out = 0; +char in_trace[254]; +char out_trace[254]; +#endif + +void usb_cinit(void *config) +{ +#if defined(SERIAL_TRACE) + in = 0; + out = 0; + memset(in_trace, 0, sizeof(in_trace)); + memset(out_trace, 0, sizeof(out_trace)); +#endif + g_init = strdup(config ? (char *) config : ""); + char *pt = strtok((char *) g_init, ","); + + if (pt != NULL) { + g_device = pt; + } + + int fd = open(g_device, O_RDWR | O_NONBLOCK); + + if (fd >= 0) { + g_usb_df = fd; + free(g_init); + } +} +void usb_cfini(void) +{ + close(g_usb_df); + g_usb_df = -1; +} +int usb_cin(void) +{ + int c = -1; + + if (g_usb_df < 0) { + + int fd = open(g_device, O_RDWR | O_NONBLOCK); + + if (fd < 0) { + return c; + } + + g_usb_df = fd; + free(g_init); + } + + char b; + + if (read(g_usb_df, &b, 1) == 1) { + c = b; +#if defined(SERIAL_TRACE) + in_trace[in] = b; + in++; + in &= 255; +#endif + } + + return c; +} +void usb_cout(uint8_t *buf, unsigned len) +{ + uint32_t timeout = 1000; + + for (unsigned i = 0; i < len; i++) { + while (timeout) { + if (write(g_usb_df, &buf[i], 1) == 1) { +#if defined(SERIAL_TRACE) + out_trace[out] = buf[i]; + out++; + out &= 255; +#endif + timeout = 1000; + break; + + } else { + if (timeout-- == 0) { + return; + } + } + } + } +} diff --git a/platforms/nuttx/src/bootloader/lib/flash_cache.c b/platforms/nuttx/src/bootloader/lib/flash_cache.c new file mode 100644 index 0000000000..b84201d961 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/flash_cache.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * + * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include +#include "flash_cache.h" + +#include "hw_config.h" + +#include + + +flash_cache_line_t flash_cache[FC_NUMBER_LINES]; + + +static inline void fcl_reset(flash_cache_line_t *fcl) +{ + memset(fcl, 0xff, sizeof(flash_cache_line_t)); +} + +inline void fc_reset(void) +{ + for (unsigned w = 0; w < FC_NUMBER_LINES; w++) { + fcl_reset(&flash_cache[w]); + } + + flash_cache[0].start_address = APP_LOAD_ADDRESS; +} + +static inline flash_cache_line_t *fc_line_select(uint32_t address) +{ + for (unsigned w = 0; w < FC_NUMBER_LINES; w++) { + if (flash_cache[w].start_address == (address & FC_ADDRESS_MASK)) { + return &flash_cache[w]; + } + } + + return NULL; +} + +inline int fc_is_dirty(flash_cache_line_t *fl) +{ + return fl->index != FC_CLEAN; +} + + +int fc_flush(flash_cache_line_t *fl) +{ + size_t bytes = (fl->index + 1) * sizeof(fl->words[0]); + size_t rv = up_progmem_write(fl->start_address, fl->words, bytes); + + if (rv == bytes) { + rv = 0; + } + + return rv; +} + +int fc_write(uint32_t address, uint32_t word) +{ + flash_cache_line_t *fc = fc_line_select(address); + flash_cache_line_t *fc1 = &flash_cache[1]; + uint32_t index = FC_ADDR2INDX(address); + int rv = 0; + + if (fc == NULL && index == 0) { + fc = fc1; + fc->start_address = address; + } + + if (fc) { + + fc->words[index] = word; + + // Are we back writing the first word? + + if (fc == &flash_cache[0] && index == 0 && fc->index == 7) { + + if (fc_is_dirty(fc1)) { + + // write out last fragment of data + + rv = fc_flush(fc1); + + if (rv != 0) { + fcl_reset(fc1); + return -1; + } + } + + rv = fc_flush(fc); + fcl_reset(fc); + return rv; + } + + fc->index = index; + } + + return rv; +} + +uint32_t fc_read(uint32_t address) +{ + // Assume a cache miss read from FLASH memory + + uint32_t rv = *(uint32_t *) address; + + flash_cache_line_t *fc = fc_line_select(address); + + if (fc) { + + // Cache hit retrieve word from cache + + uint32_t index = FC_ADDR2INDX(address); + rv = fc->words[index]; + + // Reading the last word in cache (not first words) + + if (fc != &flash_cache[0] && index == FC_LAST_WORD) { + if (fc_flush(fc)) { + rv ^= 0xffffffff; + + } else { + fcl_reset(fc); + } + } + } + + return rv; +} diff --git a/platforms/nuttx/src/bootloader/lib/flash_cache.h b/platforms/nuttx/src/bootloader/lib/flash_cache.h new file mode 100644 index 0000000000..de180e8792 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/flash_cache.h @@ -0,0 +1,69 @@ +/**************************************************************************** + * + * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +#pragma once + +/* The modern flash controllers manage flash for ECC + * On the H7 there is a block size (256) bits + * This code translates between the bootloaders word read/write + * interface and the H7 need for block based writes. + * + * All writes* are buffered until 8 word can be written. + * Verification is made from the cache. On the verification of the + * 8th word all the wordfs in the the cache are written to flash. + * If the write fails the value returned for the last word is negated + * to ensure an error on verification. + * + * *writes to the first 8 words of flash at APP_LOAD_ADDRESS + * are buffered until the "first word" is written with the real value (not 0xffffffff) + * + */ + +#define FC_NUMBER_LINES 2 // Number of cache lines. +#define FC_NUMBER_WORDS 8 // Number of words per cache line. +#define FC_LAST_WORD FC_NUMBER_WORDS-1 // The index of the last word in cache line. +#define FC_ADDRESS_MASK ~(sizeof(flash_cache[0].words)-1) // Cache tag from address +#define FC_ADDR2INDX(a) (((a) / sizeof(flash_cache[0].words[0])) % FC_NUMBER_WORDS) // index from address +#define FC_CLEAN ((uint32_t)-1) // Cache clean + +// Cache line +typedef struct flash_cache_line_t { + uint32_t index; // Index of word written + uint32_t start_address; // cache tag (address in FLASH this is buffering) + uint32_t words[FC_NUMBER_WORDS]; // Buffered data +} flash_cache_line_t; + +// Resets the cache - all lines flashed and cache_line[0] start_address == APP_LOAD_ADDRESS +void fc_reset(void); +// Cache operations +uint32_t fc_read(uint32_t address); +int fc_write(uint32_t address, uint32_t word); diff --git a/platforms/nuttx/src/bootloader/lib/systick.c b/platforms/nuttx/src/bootloader/lib/systick.c new file mode 100644 index 0000000000..482993e1d2 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/systick.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * + * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include "up_arch.h" +#include "systick.h" +#include + +uint8_t systick_get_countflag(void) +{ + return (getreg32(NVIC_SYSTICK_CTRL) & NVIC_SYSTICK_CTRL_COUNTFLAG) ? 1 : 0; +} + +// See 2.2.3 SysTick external clock is not HCLK/8 +uint32_t g_divisor = 1; +void systick_set_reload(uint32_t value) +{ + putreg32((((value * g_divisor) << NVIC_SYSTICK_RELOAD_SHIFT) & NVIC_SYSTICK_RELOAD_MASK), NVIC_SYSTICK_RELOAD); +} + + +void systick_set_clocksource(uint8_t clocksource) +{ + g_divisor = (clocksource == CLKSOURCE_EXTERNAL) ? 8 : 1; + modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_CLKSOURCE, clocksource & NVIC_SYSTICK_CTRL_CLKSOURCE); +} + +void systick_counter_enable(void) +{ + modifyreg32(NVIC_SYSTICK_CTRL, 0, NVIC_SYSTICK_CTRL_ENABLE); +} + +void systick_counter_disable(void) +{ + modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_ENABLE, 0); + putreg32(0, NVIC_SYSTICK_CURRENT); +} + +void systick_interrupt_enable(void) +{ + modifyreg32(NVIC_SYSTICK_CTRL, 0, NVIC_SYSTICK_CTRL_TICKINT); +} + +void systick_interrupt_disable(void) +{ + modifyreg32(NVIC_SYSTICK_CTRL, NVIC_SYSTICK_CTRL_TICKINT, 0); +} diff --git a/platforms/nuttx/src/bootloader/lib/systick.h b/platforms/nuttx/src/bootloader/lib/systick.h new file mode 100644 index 0000000000..c5454dbece --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/systick.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * + * Copyright (c) 2016 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +#pragma once + +#define CLKSOURCE_EXTERNAL 0 +#define CLKSOURCE_PROCESOR NVIC_SYSTICK_CTRL_CLKSOURCE + +uint8_t systick_get_countflag(void); +void systick_set_reload(uint32_t value); +void systick_set_clocksource(uint8_t clocksource); +void systick_counter_enable(void); +void systick_counter_disable(void); +void systick_interrupt_enable(void); +void systick_interrupt_disable(void); diff --git a/platforms/nuttx/src/bootloader/lib/uart.c b/platforms/nuttx/src/bootloader/lib/uart.c new file mode 100644 index 0000000000..aeb48193f5 --- /dev/null +++ b/platforms/nuttx/src/bootloader/lib/uart.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * + * Copyright (c) 2019 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include "uart.h" +#include +#include +#include +#include +//#define SERIAL_TRACE + +int g_uart_df = -1; + +#if defined(SERIAL_TRACE) +int in = 0; +int out = 0; +char in_trace[254]; +char out_trace[254]; +#endif + + +void uart_cinit(void *config) +{ + char *init = strdup(config ? (char *) config : ""); + char *pt = strtok((char *) init, ","); + char *device = "/dev/ttyS0"; + int baud = 115200; + + if (pt != NULL) { + device = pt; + pt = strtok(NULL, ","); + + if (pt != NULL) { + baud = atol(pt); + } + } + + int fd = open(device, O_RDWR | O_NONBLOCK); + + if (fd >= 0) { + + g_uart_df = fd; + struct termios t; + + tcgetattr(g_uart_df, &t); + t.c_cflag &= ~(CSIZE | PARENB | CSTOPB); + t.c_cflag |= (CS8); + cfsetspeed(&t, baud); + tcsetattr(g_uart_df, TCSANOW, &t); + } + + free(init); +} + +void uart_cfini(void) +{ + close(g_uart_df); + g_uart_df = -1; +} +int uart_cin(void) +{ + int c = -1; + + if (g_uart_df >= 0) { + char b; + + if (read(g_uart_df, &b, 1) == 1) { + c = b; +#if defined(SERIAL_TRACE) + in_trace[in] = b; + in++; + in &= 255; +#endif + } + } + + return c; +} +void uart_cout(uint8_t *buf, unsigned len) +{ + uint32_t timeout = 1000; + + for (unsigned i = 0; i < len; i++) { + while (timeout) { + if (write(g_uart_df, &buf[i], 1) == 1) { +#if defined(SERIAL_TRACE) + out_trace[out] = buf[i]; + out++; + out &= 255; +#endif + timeout = 1000; + break; + + } else { + if (timeout-- == 0) { + return; + } + } + } + } +} diff --git a/platforms/nuttx/src/bootloader/stm32h7/main.c b/platforms/nuttx/src/bootloader/stm32h7/main.c new file mode 100644 index 0000000000..b788e2659d --- /dev/null +++ b/platforms/nuttx/src/bootloader/stm32h7/main.c @@ -0,0 +1,802 @@ +/* + * STM32F7 board support for the bootloader. + * + */ + +#include +#include + +#include "hw_config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "bl.h" +#include "uart.h" + + +#define MK_GPIO_INPUT(def) (((def) & (GPIO_PORT_MASK | GPIO_PIN_MASK)) | (GPIO_INPUT)) + +#define BOOTLOADER_RESERVATION_SIZE (128 * 1024) + +//STM DocID018909 Rev 8 Sect 38.18 and DocID026670 Rev 5 40.6.1 (MCU device ID code) +# define REVID_MASK 0xFFFF0000 +# define DEVID_MASK 0xFFF + + +/* magic numbers from reference manual */ +#define STM32_UNKNOWN 0 +#define STM32H74xx_75xx 0x450 +#define STM32F74xxx_75xxx 0x449 + +typedef enum mcu_rev_e { + MCU_REV_Z = 0x1001, + MCU_REV_Y = 0x1003, + MCU_REV_X = 0x2001, + MCU_REV_V = 0x2003 +} mcu_rev_e; + +typedef struct mcu_des_t { + uint16_t mcuid; + const char *desc; + char rev; +} mcu_des_t; + +// The default CPU ID of STM32_UNKNOWN is 0 and is in offset 0 +// Before a rev is known it is set to ? +// There for new silicon will result in STM32F4..,? +mcu_des_t mcu_descriptions[] = { + { STM32_UNKNOWN, "STM32???????", '?'}, + { STM32H74xx_75xx, "STM32H7[4|5]x", '?'}, +}; + +typedef struct mcu_rev_t { + mcu_rev_e revid; + char rev; +} mcu_rev_t; + +/* + * This table is used to look look up the revision + * of a given chip. + */ +const mcu_rev_t silicon_revs[] = { + {MCU_REV_Y, 'Y'}, /* Revision Y */ + {MCU_REV_X, 'X'}, /* Revision X */ + {MCU_REV_V, 'V'}, /* Revision V */ + {MCU_REV_Z, 'Z'}, /* Revision Z */ +}; + +#define APP_SIZE_MAX (BOARD_FLASH_SIZE - (BOOTLOADER_RESERVATION_SIZE + APP_RESERVATION_SIZE)) + + +/* context passed to cinit */ +#if INTERFACE_USART +# define BOARD_INTERFACE_CONFIG_USART INTERFACE_USART_CONFIG +#endif +#if INTERFACE_USB +# define BOARD_INTERFACE_CONFIG_USB INTERFACE_USB_CONFIG +#endif + +/* board definition */ +struct boardinfo board_info = { + .board_type = BOARD_TYPE, + .board_rev = 0, + .fw_size = 0, + .systick_mhz = 416, +}; + +static void board_init(void); + +#define BOOT_RTC_SIGNATURE 0xb007b007 +#define BOOT_RTC_REG MMIO32(RTC_BASE + 0x50) + +/* State of an inserted USB cable */ +static bool usb_connected = false; + +static uint32_t board_get_rtc_signature(void) +{ + /* enable the backup registers */ + stm32_pwr_initbkp(true); + + uint32_t result = getreg32(STM32_RTC_BK0R); + + /* disable the backup registers */ + stm32_pwr_initbkp(false); + + return result; +} + +static void +board_set_rtc_signature(uint32_t sig) +{ + /* enable the backup registers */ + stm32_pwr_initbkp(true); + + putreg32(sig, STM32_RTC_BK0R); + + /* disable the backup registers */ + stm32_pwr_initbkp(false); + +} + +static bool board_test_force_pin(void) +{ +#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT) + /* two pins strapped together */ + volatile unsigned samples = 0; + volatile unsigned vote = 0; + + for (volatile unsigned cycles = 0; cycles < 10; cycles++) { + px4_arch_gpiowrite(BOARD_FORCE_BL_PIN_OUT, 1); + + for (unsigned count = 0; count < 20; count++) { + if (px4_arch_gpioread(BOARD_FORCE_BL_PIN_IN) != 0) { + vote++; + } + + samples++; + } + + px4_arch_gpiowrite(BOARD_FORCE_BL_PIN_OUT, 0); + + for (unsigned count = 0; count < 20; count++) { + if (px4_arch_gpioread(BOARD_FORCE_BL_PIN_IN) == 0) { + vote++; + } + + samples++; + } + } + + /* the idea here is to reject wire-to-wire coupling, so require > 90% agreement */ + if ((vote * 100) > (samples * 90)) { + return true; + } + +#endif +#if defined(BOARD_FORCE_BL_PIN) + /* single pin pulled up or down */ + volatile unsigned samples = 0; + volatile unsigned vote = 0; + + for (samples = 0; samples < 200; samples++) { + if ((px4_arch_gpioread(BOARD_FORCE_BL_PIN) ? 1 : 0) == BOARD_FORCE_BL_STATE) { + vote++; + } + } + + /* reject a little noise */ + if ((vote * 100) > (samples * 90)) { + return true; + } + +#endif + return false; +} + +#if INTERFACE_USART +static bool board_test_usart_receiving_break(void) +{ +#if !defined(SERIAL_BREAK_DETECT_DISABLED) + /* (re)start the SysTick timer system */ + systick_interrupt_disable(); // Kill the interrupt if it is still active + systick_counter_disable(); // Stop the timer + systick_set_clocksource(CLKSOURCE_PROCESOR); + + /* Set the timer period to be half the bit rate + * + * Baud rate = 115200, therefore bit period = 8.68us + * Half the bit rate = 4.34us + * Set period to 4.34 microseconds (timer_period = timer_tick / timer_reset_frequency = 168MHz / (1/4.34us) = 729.12 ~= 729) + */ + systick_set_reload(729); /* 4.3us tick, magic number */ + systick_counter_enable(); // Start the timer + + uint8_t cnt_consecutive_low = 0; + uint8_t cnt = 0; + + /* Loop for 3 transmission byte cycles and count the low and high bits. Sampled at a rate to be able to count each bit twice. + * + * One transmission byte is 10 bits (8 bytes of data + 1 start bit + 1 stop bit) + * We sample at every half bit time, therefore 20 samples per transmission byte, + * therefore 60 samples for 3 transmission bytes + */ + while (cnt < 60) { + // Only read pin when SysTick timer is true + if (systick_get_countflag() == 1) { + if (gpio_get(BOARD_PORT_USART_RX, BOARD_PIN_RX) == 0) { + cnt_consecutive_low++; // Increment the consecutive low counter + + } else { + cnt_consecutive_low = 0; // Reset the consecutive low counter + } + + cnt++; + } + + // If 9 consecutive low bits were received break out of the loop + if (cnt_consecutive_low >= 18) { + break; + } + + } + + systick_counter_disable(); // Stop the timer + + /* + * If a break is detected, return true, else false + * + * Break is detected if line was low for 9 consecutive bits. + */ + if (cnt_consecutive_low >= 18) { + return true; + } + +#endif // !defined(SERIAL_BREAK_DETECT_DISABLED) + + return false; +} +#endif + +uint32_t +board_get_devices(void) +{ + uint32_t devices = BOOT_DEVICES_SELECTION; + + if (usb_connected) { + devices &= BOOT_DEVICES_FILTER_ONUSB; + } + + return devices; +} + +static void +board_init(void) +{ + /* fix up the max firmware size, we have to read memory to get this */ + board_info.fw_size = APP_SIZE_MAX; + +#if defined(BOARD_POWER_PIN_OUT) + /* Configure the Power pins */ + px4_arch_configgpio(BOARD_POWER_PIN_OUT); + px4_arch_gpiowrite(BOARD_POWER_PIN_OUT, BOARD_POWER_ON); +#endif + +#if INTERFACE_USB +#if !defined(BOARD_USB_VBUS_SENSE_DISABLED) + /* enable configured GPIO to sample VBUS */ +# if defined(USE_VBUS_PULL_DOWN) + px4_arch_configgpio((GPIO_OTGFS_VBUS & GPIO_PUPD_MASK) | GPIO_PULLDOWN); +# else + px4_arch_configgpio((GPIO_OTGFS_VBUS & GPIO_PUPD_MASK) | GPIO_FLOAT); +# endif +#endif +#endif + +#if INTERFACE_USART +#endif + +#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT) + /* configure the force BL pins */ + px4_arch_configgpio(BOARD_FORCE_BL_PIN_IN); + px4_arch_configgpio(BOARD_FORCE_BL_PIN_OUT); +#endif + +#if defined(BOARD_FORCE_BL_PIN) + /* configure the force BL pins */ + px4_arch_configgpio(BOARD_FORCE_BL_PIN); +#endif + +#if defined(BOARD_PIN_LED_ACTIVITY) + /* Initialize LEDs */ + px4_arch_configgpio(BOARD_PIN_LED_ACTIVITY); +#endif +#if defined(BOARD_PIN_LED_BOOTLOADER) + /* Initialize LEDs */ + px4_arch_configgpio(BOARD_PIN_LED_BOOTLOADER); +#endif +} + +void +board_deinit(void) +{ + +#if INTERFACE_USART +#endif + +#if INTERFACE_USB + px4_arch_configgpio(MK_GPIO_INPUT(GPIO_OTGFS_VBUS)); +#endif + +#if defined(BOARD_FORCE_BL_PIN_IN) && defined(BOARD_FORCE_BL_PIN_OUT) + /* deinitialise the force BL pins */ + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN_IN)); + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN_OUT)); +#endif + +#if defined(BOARD_FORCE_BL_PIN) + /* deinitialise the force BL pin */ + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_FORCE_BL_PIN)); +#endif + +#if defined(BOARD_POWER_PIN_OUT) && defined(BOARD_POWER_PIN_RELEASE) + /* deinitialize the POWER pin - with the assumption the hold up time of + * the voltage being bleed off by an inupt pin impedance will allow + * enough time to boot the app + */ + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_POWER_PIN_OUT)); +#endif + +#if defined(BOARD_PIN_LED_ACTIVITY) + /* Initialize LEDs */ + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_PIN_LED_ACTIVITY)); +#endif +#if defined(BOARD_PIN_LED_BOOTLOADER) + /* Initialize LEDs */ + px4_arch_configgpio(MK_GPIO_INPUT(BOARD_PIN_LED_BOOTLOADER)); +#endif + + + /* disable the AHB peripheral clocks */ + putreg32(0, STM32_RCC_AHB1ENR); +} + +inline void arch_systic_init(void) +{ + /* (re)start the timer system */ + systick_set_clocksource(CLKSOURCE_PROCESOR); + systick_set_reload(board_info.systick_mhz * 1000); /* 1ms tick, magic number */ + systick_interrupt_enable(); + systick_counter_enable(); +} + +inline void arch_systic_deinit(void) +{ + /* kill the systick interrupt */ + systick_interrupt_disable(); + systick_counter_disable(); + systick_set_clocksource(CLKSOURCE_EXTERNAL); + systick_set_reload(0); /* 1ms tick, magic number */ +} + +/** + * @brief Initializes the RCC clock configuration. + * + * @param clock_setup : The clock configuration to set + */ +static inline void +clock_init(void) +{ + // Done by Nuttx +} + +/** + * @brief Resets the RCC clock configuration to the default reset state. + * @note The default reset state of the clock configuration is given below: + * - HSI ON and used as system clock source + * - HSE, PLL and PLLI2S OFF + * - AHB, APB1 and APB2 prescaler set to 1. + * - CSS, MCO1 and MCO2 OFF + * - All interrupts disabled + * @note This function doesn't modify the configuration of the + * - Peripheral clocks + * - LSI, LSE and RTC clocks + */ +void +clock_deinit(void) +{ + uint32_t regval; + + /* Enable internal high-speed oscillator. */ + + regval = getreg32(STM32_RCC_CR); + regval |= RCC_CR_HSION; + putreg32(regval, STM32_RCC_CR); + + /* Check if the HSIRDY flag is the set in the CR */ + + while ((getreg32(STM32_RCC_CR) & RCC_CR_HSIRDY) == 0); + + /* Reset the RCC_CFGR register */ + putreg32(0, STM32_RCC_CFGR); + + /* Stop the HSE, CSS, PLL, PLLI2S, PLLSAI */ + regval = getreg32(STM32_RCC_CR); + regval &= ~(RCC_CR_HSEON | RCC_CR_PLL1ON | RCC_CR_PLL2ON | RCC_CR_PLL3ON | RCC_CR_CSSHSEON); + putreg32(regval, STM32_RCC_CR); + + /* Reset the RCC_PLLCFGR register */ + putreg32(0x01FF0000, STM32_RCC_PLLCFGR); + + /* Reset the HSEBYP bit */ + regval = getreg32(STM32_RCC_CR); + regval &= ~(RCC_CR_HSEBYP); + putreg32(regval, STM32_RCC_CR); + +} + +inline void arch_flash_lock(void) +{ + stm32h7_flash_lock(STM32_FLASH_BANK1); + stm32h7_flash_lock(STM32_FLASH_BANK2); +} + +inline void arch_flash_unlock(void) +{ + fc_reset(); + stm32h7_flash_unlock(STM32_FLASH_BANK1); + stm32h7_flash_unlock(STM32_FLASH_BANK2); +} + +inline void arch_setvtor(uint32_t address) +{ + putreg32(address, NVIC_VECTAB); +} + +uint32_t +flash_func_sector_size(unsigned sector) +{ + if (sector <= BOARD_FLASH_SECTORS) { + return 128 * 1024; + } + + return 0; +} + +void +flash_func_erase_sector(unsigned sector) +{ + if (sector > BOARD_FLASH_SECTORS || (int)sector < BOARD_FIRST_FLASH_SECTOR_TO_ERASE) { + return; + } + + /* blank-check the sector */ + + bool blank = up_progmem_ispageerased(sector) == 0; + + /* erase the sector if it failed the blank check */ + if (!blank) { + up_progmem_eraseblock(sector); + } +} + +void +flash_func_write_word(uint32_t address, uint32_t word) +{ + address += APP_LOAD_ADDRESS; + fc_write(address, word); +} + +uint32_t flash_func_read_word(uint32_t address) +{ + + if (address & 3) { + return 0; + } + + return fc_read(address + APP_LOAD_ADDRESS); + +} + + +uint32_t +flash_func_read_otp(uint32_t address) +{ + return 0; +} + +uint32_t get_mcu_id(void) +{ + return *(uint32_t *)STM32_DEBUGMCU_BASE; +} + +int get_mcu_desc(int max, uint8_t *revstr) +{ + uint32_t idcode = (*(uint32_t *) STM32_DEBUGMCU_BASE); + int32_t mcuid = idcode & DEVID_MASK; + mcu_rev_e revid = (idcode & REVID_MASK) >> 16; + + mcu_des_t des = mcu_descriptions[STM32_UNKNOWN]; + + for (unsigned int i = 0; i < arraySize(mcu_descriptions); i++) { + if (mcuid == mcu_descriptions[i].mcuid) { + des = mcu_descriptions[i]; + break; + } + } + + for (unsigned int i = 0; i < arraySize(silicon_revs); i++) { + if (silicon_revs[i].revid == revid) { + des.rev = silicon_revs[i].rev; + } + } + + uint8_t *endp = &revstr[max - 1]; + uint8_t *strp = revstr; + + while (strp < endp && *des.desc) { + *strp++ = *des.desc++; + } + + if (strp < endp) { + *strp++ = ','; + } + + if (strp < endp) { + *strp++ = des.rev; + } + + return strp - revstr; +} + + +int check_silicon(void) +{ + return 0; +} + +uint32_t +flash_func_read_sn(uint32_t address) +{ + // read a byte out from unique chip ID area + // it's 12 bytes, or 3 words. + return *(uint32_t *)(address + STM32_SYSMEM_UID); +} + +void +led_on(unsigned led) +{ + switch (led) { + case LED_ACTIVITY: +#if defined(BOARD_PIN_LED_ACTIVITY) + px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, BOARD_LED_ON); +#endif + break; + + case LED_BOOTLOADER: +#if defined(BOARD_PIN_LED_BOOTLOADER) + px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, BOARD_LED_ON); +#endif + break; + } +} + +void +led_off(unsigned led) +{ + switch (led) { + case LED_ACTIVITY: +#if defined(BOARD_PIN_LED_ACTIVITY) + px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, BOARD_LED_OFF); +#endif + break; + + case LED_BOOTLOADER: +#if defined(BOARD_PIN_LED_BOOTLOADER) + px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, BOARD_LED_OFF); +#endif + break; + } +} + +void +led_toggle(unsigned led) +{ + switch (led) { + case LED_ACTIVITY: +#if defined(BOARD_PIN_LED_ACTIVITY) + px4_arch_gpiowrite(BOARD_PIN_LED_ACTIVITY, px4_arch_gpioread(BOARD_PIN_LED_ACTIVITY) ^ 1); +#endif + break; + + case LED_BOOTLOADER: +#if defined(BOARD_PIN_LED_BOOTLOADER) + px4_arch_gpiowrite(BOARD_PIN_LED_BOOTLOADER, px4_arch_gpioread(BOARD_PIN_LED_BOOTLOADER) ^ 1); +#endif + break; + } +} + +/* we should know this, but we don't */ +#ifndef SCB_CPACR +# define SCB_CPACR (*((volatile uint32_t *) (((0xE000E000UL) + 0x0D00UL) + 0x088))) +#endif + +int +bootloader_main(void) +{ + bool try_boot = true; /* try booting before we drop to the bootloader */ + unsigned timeout = BOOTLOADER_DELAY; /* if nonzero, drop out of the bootloader after this time */ + + /* Enable the FPU before we hit any FP instructions */ + SCB_CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 Full Access and set CP11 Full Access */ + +#if defined(BOARD_POWER_PIN_OUT) + + /* Here we check for the app setting the POWER_DOWN_RTC_SIGNATURE + * in this case, we reset the signature and wait to die + */ + if (board_get_rtc_signature() == POWER_DOWN_RTC_SIGNATURE) { + board_set_rtc_signature(0); + + while (1); + } + +#endif + + /* do board-specific initialisation */ + board_init(); + + /* configure the clock for bootloader activity */ + clock_init(); + + /* + * Check the force-bootloader register; if we find the signature there, don't + * try booting. + */ + if (board_get_rtc_signature() == BOOT_RTC_SIGNATURE) { + + /* + * Don't even try to boot before dropping to the bootloader. + */ + try_boot = false; + + /* + * Don't drop out of the bootloader until something has been uploaded. + */ + timeout = 0; + + /* + * Clear the signature so that if someone resets us while we're + * in the bootloader we'll try to boot next time. + */ + board_set_rtc_signature(0); + } + +#ifdef BOOT_DELAY_ADDRESS + { + /* + if a boot delay signature is present then delay the boot + by at least that amount of time in seconds. This allows + for an opportunity for a companion computer to load a + new firmware, while still booting fast by sending a BOOT + command + */ + uint32_t sig1 = flash_func_read_word(BOOT_DELAY_ADDRESS); + uint32_t sig2 = flash_func_read_word(BOOT_DELAY_ADDRESS + 4); + + if (sig2 == BOOT_DELAY_SIGNATURE2 && + (sig1 & 0xFFFFFF00) == (BOOT_DELAY_SIGNATURE1 & 0xFFFFFF00)) { + unsigned boot_delay = sig1 & 0xFF; + + if (boot_delay <= BOOT_DELAY_MAX) { + try_boot = false; + + if (timeout < boot_delay * 1000) { + timeout = boot_delay * 1000; + } + } + } + } +#endif + + /* + * Check if the force-bootloader pins are strapped; if strapped, + * don't try booting. + */ + if (board_test_force_pin()) { + try_boot = false; + } + +#if INTERFACE_USB + + /* + * Check for USB connection - if present, don't try to boot, but set a timeout after + * which we will fall out of the bootloader. + * + * If the force-bootloader pins are tied, we will stay here until they are removed and + * we then time out. + */ +#if defined(BOARD_VBUS) + + if (px4_arch_gpioread(BOARD_VBUS) != 0) { + usb_connected = true; + /* don't try booting before we set up the bootloader */ + try_boot = false; + } + +#else + try_boot = false; + +#endif +#endif + +#if INTERFACE_USART + + /* + * Check for if the USART port RX line is receiving a break command, or is being held low. If yes, + * don't try to boot, but set a timeout after + * which we will fall out of the bootloader. + * + * If the force-bootloader pins are tied, we will stay here until they are removed and + * we then time out. + */ + if (board_test_usart_receiving_break()) { + try_boot = false; + } + +#endif + + /* Try to boot the app if we think we should just go straight there */ + if (try_boot) { + + /* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */ +#ifdef BOARD_BOOT_FAIL_DETECT + board_set_rtc_signature(BOOT_RTC_SIGNATURE); +#endif + + /* try to boot immediately */ + jump_to_app(); + + // If it failed to boot, reset the boot signature and stay in bootloader + board_set_rtc_signature(BOOT_RTC_SIGNATURE); + + /* booting failed, stay in the bootloader forever */ + timeout = 0; + } + + + /* start the interface */ +#if INTERFACE_USART + cinit(BOARD_INTERFACE_CONFIG_USART, USART); +#endif +#if INTERFACE_USB + cinit(BOARD_INTERFACE_CONFIG_USB, USB); +#endif + + +#if 0 + // MCO1/02 + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); + gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO8); + gpio_set_af(GPIOA, GPIO_AF0, GPIO8); + gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); + gpio_set_af(GPIOC, GPIO_AF0, GPIO9); +#endif + + + while (1) { + /* run the bootloader, come back after an app is uploaded or we time out */ + bootloader(timeout); + + /* if the force-bootloader pins are strapped, just loop back */ + if (board_test_force_pin()) { + continue; + } + +#if INTERFACE_USART + + /* if the USART port RX line is still receiving a break, just loop back */ + if (board_test_usart_receiving_break()) { + continue; + } + +#endif + + /* set the boot-to-bootloader flag so that if boot fails on reset we will stop here */ +#ifdef BOARD_BOOT_FAIL_DETECT + board_set_rtc_signature(BOOT_RTC_SIGNATURE); +#endif + + /* look to see if we can boot the app */ + jump_to_app(); + + /* launching the app failed - stay in the bootloader forever */ + timeout = 0; + } +} diff --git a/platforms/nuttx/src/bootloader/uart.h b/platforms/nuttx/src/bootloader/uart.h new file mode 100644 index 0000000000..2059fce057 --- /dev/null +++ b/platforms/nuttx/src/bootloader/uart.h @@ -0,0 +1,45 @@ +/**************************************************************************** + * + * Copyright (c) 2012-2014 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/** + * @file uart.h + * + * UART bootloader definitions. + */ + +#pragma once + +extern void uart_cinit(void *config); +extern void uart_cfini(void); +extern int uart_cin(void); +extern void uart_cout(uint8_t *buf, unsigned len);