mirror of https://github.com/ArduPilot/ardupilot
AP_Bootloader: fully working on H7
This commit is contained in:
parent
599a1a3d67
commit
ac070c92f5
|
@ -40,6 +40,7 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include <AP_HAL/AP_HAL.h>
|
#include <AP_HAL/AP_HAL.h>
|
||||||
|
#include <AP_Math/AP_Math.h>
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
#include "hwdef.h"
|
#include "hwdef.h"
|
||||||
|
@ -47,6 +48,8 @@
|
||||||
#include "bl_protocol.h"
|
#include "bl_protocol.h"
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
|
|
||||||
|
// #pragma GCC optimize("O0")
|
||||||
|
|
||||||
|
|
||||||
// bootloader flash update protocol.
|
// bootloader flash update protocol.
|
||||||
//
|
//
|
||||||
|
@ -125,6 +128,10 @@ static enum led_state {LED_BLINK, LED_ON, LED_OFF} led_state;
|
||||||
|
|
||||||
volatile unsigned timer[NTIMERS];
|
volatile unsigned timer[NTIMERS];
|
||||||
|
|
||||||
|
// keep back 32 bytes at the front of flash. This is long enough to allow for aligned
|
||||||
|
// access on STM32H7
|
||||||
|
#define RESERVE_LEAD_WORDS 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1ms timer tick callback
|
1ms timer tick callback
|
||||||
*/
|
*/
|
||||||
|
@ -174,7 +181,7 @@ led_set(enum led_state state)
|
||||||
static void
|
static void
|
||||||
do_jump(uint32_t stacktop, uint32_t entrypoint)
|
do_jump(uint32_t stacktop, uint32_t entrypoint)
|
||||||
{
|
{
|
||||||
#if defined(STM32F7)
|
#if defined(STM32F7) || defined(STM32H7)
|
||||||
// disable caches on F7 before starting program
|
// disable caches on F7 before starting program
|
||||||
__DSB();
|
__DSB();
|
||||||
__ISB();
|
__ISB();
|
||||||
|
@ -200,11 +207,14 @@ jump_to_app()
|
||||||
const uint32_t *app_base = (const uint32_t *)(APP_START_ADDRESS);
|
const uint32_t *app_base = (const uint32_t *)(APP_START_ADDRESS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We refuse to program the first word of the app until the upload is marked
|
* We hold back the programming of the lead words until the upload
|
||||||
* complete by the host. So if it's not 0xffffffff, we should try booting it.
|
* is marked complete by the host. So if they are not 0xffffffff,
|
||||||
|
* we should try booting it.
|
||||||
*/
|
*/
|
||||||
if (app_base[0] == 0xffffffff) {
|
for (uint8_t i=0; i<RESERVE_LEAD_WORDS; i++) {
|
||||||
return;
|
if (app_base[i] == 0xffffffff) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -330,15 +340,68 @@ crc32(const uint8_t *src, unsigned len, unsigned state)
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
we use a write buffer for flashing, both for efficiency and to
|
||||||
|
ensure that we only ever do 32 byte aligned writes on STM32H7. If
|
||||||
|
you attempt to do writes on a H7 of less than 32 bytes or not
|
||||||
|
aligned then the flash can end up in a CRC error state, which can
|
||||||
|
generate a hardware fault (a double ECC error) on flash read, even
|
||||||
|
after a power cycle
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
uint32_t buffer[8];
|
||||||
|
uint32_t address;
|
||||||
|
uint8_t n;
|
||||||
|
} fbuf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
flush the write buffer
|
||||||
|
*/
|
||||||
|
static bool flash_write_flush(void)
|
||||||
|
{
|
||||||
|
if (fbuf.n == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
fbuf.n = 0;
|
||||||
|
return flash_func_write_words(fbuf.address, fbuf.buffer, ARRAY_SIZE(fbuf.buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
write to flash with buffering to 32 bytes alignment
|
||||||
|
*/
|
||||||
|
static bool flash_write_buffer(uint32_t address, const uint32_t *v, uint8_t nwords)
|
||||||
|
{
|
||||||
|
if (fbuf.n > 0 && address != fbuf.address + fbuf.n*4) {
|
||||||
|
if (!flash_write_flush()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (nwords > 0) {
|
||||||
|
if (fbuf.n == 0) {
|
||||||
|
fbuf.address = address;
|
||||||
|
memset(fbuf.buffer, 0xff, sizeof(fbuf.buffer));
|
||||||
|
}
|
||||||
|
uint8_t n = MIN(ARRAY_SIZE(fbuf.buffer)-fbuf.n, nwords);
|
||||||
|
memcpy(&fbuf.buffer[fbuf.n], v, n*4);
|
||||||
|
address += n*4;
|
||||||
|
v += n;
|
||||||
|
nwords -= n;
|
||||||
|
fbuf.n += n;
|
||||||
|
if (fbuf.n == ARRAY_SIZE(fbuf.buffer)) {
|
||||||
|
if (!flash_write_flush()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#define TEST_FLASH 0
|
#define TEST_FLASH 0
|
||||||
|
|
||||||
#if TEST_FLASH
|
#if TEST_FLASH
|
||||||
static void test_flash()
|
static void test_flash()
|
||||||
{
|
{
|
||||||
for (uint8_t i=0; i<10; i++) {
|
|
||||||
uprintf("waiting %u...\n", i);
|
|
||||||
delay(300);
|
|
||||||
}
|
|
||||||
uint32_t loop = 1;
|
uint32_t loop = 1;
|
||||||
bool init_done = false;
|
bool init_done = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -395,12 +458,18 @@ bootloader(unsigned timeout)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint32_t address = board_info.fw_size; /* force erase before upload will work */
|
uint32_t address = board_info.fw_size; /* force erase before upload will work */
|
||||||
uint32_t first_word = 0xffffffff;
|
uint32_t first_words[RESERVE_LEAD_WORDS];
|
||||||
bool done_sync = false;
|
bool done_sync = false;
|
||||||
bool done_get_device = false;
|
bool done_get_device = false;
|
||||||
|
static bool done_timer_init;
|
||||||
|
|
||||||
chVTObjectInit(&systick_vt);
|
memset(first_words, 0xFF, sizeof(first_words));
|
||||||
chVTSet(&systick_vt, chTimeMS2I(1), sys_tick_handler, nullptr);
|
|
||||||
|
if (!done_timer_init) {
|
||||||
|
done_timer_init = true;
|
||||||
|
chVTObjectInit(&systick_vt);
|
||||||
|
chVTSet(&systick_vt, chTimeMS2I(1), sys_tick_handler, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* if we are working with a timeout, start it running */
|
/* if we are working with a timeout, start it running */
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
|
@ -533,7 +602,9 @@ bootloader(unsigned timeout)
|
||||||
|
|
||||||
// erase all sectors
|
// erase all sectors
|
||||||
for (uint8_t i = 0; flash_func_sector_size(i) != 0; i++) {
|
for (uint8_t i = 0; flash_func_sector_size(i) != 0; i++) {
|
||||||
flash_func_erase_sector(i);
|
if (!flash_func_erase_sector(i)) {
|
||||||
|
goto cmd_fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable the LED while verifying the erase
|
// enable the LED while verifying the erase
|
||||||
|
@ -601,18 +672,20 @@ bootloader(unsigned timeout)
|
||||||
goto cmd_bad;
|
goto cmd_bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address == 0) {
|
// save the first words and don't program it until everything else is done
|
||||||
// save the first word and don't program it until everything else is done
|
if (address < sizeof(first_words)) {
|
||||||
first_word = flash_buffer.w[0];
|
uint8_t n = MIN(sizeof(first_words)-address, arg);
|
||||||
// replace first word with bits we can overwrite later
|
memcpy(&first_words[address/4], &flash_buffer.w[0], n);
|
||||||
flash_buffer.w[0] = 0xffffffff;
|
// replace first words with 1 bits we can overwrite later
|
||||||
|
memset(&flash_buffer.w[0], 0xFF, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
arg /= 4;
|
arg /= 4;
|
||||||
// program the words
|
// program the words
|
||||||
if (!flash_func_write_words(address, flash_buffer.w, arg)) {
|
if (!flash_write_buffer(address, flash_buffer.w, arg)) {
|
||||||
goto cmd_fail;
|
goto cmd_fail;
|
||||||
}
|
}
|
||||||
|
address += arg * 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// fetch CRC of the entire flash area
|
// fetch CRC of the entire flash area
|
||||||
|
@ -626,19 +699,21 @@ bootloader(unsigned timeout)
|
||||||
goto cmd_bad;
|
goto cmd_bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!flash_write_flush()) {
|
||||||
|
goto cmd_bad;
|
||||||
|
}
|
||||||
|
|
||||||
// compute CRC of the programmed area
|
// compute CRC of the programmed area
|
||||||
uint32_t sum = 0;
|
uint32_t sum = 0;
|
||||||
|
|
||||||
for (unsigned p = 0; p < board_info.fw_size; p += 4) {
|
for (unsigned p = 0; p < board_info.fw_size; p += 4) {
|
||||||
uint32_t bytes;
|
uint32_t bytes;
|
||||||
|
|
||||||
if ((p == 0) && (first_word != 0xffffffff)) {
|
if (p < sizeof(first_words) && first_words[0] != 0xFFFFFFFF) {
|
||||||
bytes = first_word;
|
bytes = first_words[p/4];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bytes = flash_func_read_word(p);
|
bytes = flash_func_read_word(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
sum = crc32((uint8_t *)&bytes, sizeof(bytes), sum);
|
sum = crc32((uint8_t *)&bytes, sizeof(bytes), sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,16 +854,17 @@ bootloader(unsigned timeout)
|
||||||
goto cmd_bad;
|
goto cmd_bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
// program the deferred first word
|
if (!flash_write_flush()) {
|
||||||
if (first_word != 0xffffffff) {
|
goto cmd_fail;
|
||||||
flash_func_write_word(0, first_word);
|
}
|
||||||
|
|
||||||
if (flash_func_read_word(0) != first_word) {
|
// program the deferred first word
|
||||||
|
if (first_words[0] != 0xffffffff) {
|
||||||
|
if (!flash_write_buffer(0, first_words, RESERVE_LEAD_WORDS)) {
|
||||||
goto cmd_fail;
|
goto cmd_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert in case the flash was bad...
|
// revert in case the flash was bad...
|
||||||
first_word = 0xffffffff;
|
memset(first_words, 0xff, sizeof(first_words));
|
||||||
}
|
}
|
||||||
|
|
||||||
// send a sync and wait for it to be collected
|
// send a sync and wait for it to be collected
|
||||||
|
|
|
@ -25,6 +25,8 @@ static uint8_t last_uart;
|
||||||
#define BOOTLOADER_BAUDRATE 115200
|
#define BOOTLOADER_BAUDRATE 115200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// #pragma GCC optimize("O0")
|
||||||
|
|
||||||
int16_t cin(unsigned timeout_ms)
|
int16_t cin(unsigned timeout_ms)
|
||||||
{
|
{
|
||||||
uint8_t b = 0;
|
uint8_t b = 0;
|
||||||
|
@ -254,12 +256,18 @@ extern "C" {
|
||||||
void uprintf(const char *fmt, ...)
|
void uprintf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
#if HAL_USE_SERIAL_USB == TRUE
|
#if HAL_USE_SERIAL_USB == TRUE
|
||||||
char msg[200];
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
static bool initialised;
|
||||||
|
char umsg[200];
|
||||||
|
if (!initialised) {
|
||||||
|
initialised = true;
|
||||||
|
sercfg.speed = 57600;
|
||||||
|
sdStart(&SD7, &sercfg);
|
||||||
|
}
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
uint32_t n = vsnprintf(msg, sizeof(msg), fmt, ap);
|
uint32_t n = vsnprintf(umsg, sizeof(umsg), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
chnWriteTimeout(&SDU1, (const uint8_t *)msg, n, chTimeMS2I(100));
|
chnWriteTimeout(&SD7, (const uint8_t *)umsg, n, chTimeMS2I(100));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ void led_on(unsigned led);
|
||||||
void led_off(unsigned led);
|
void led_off(unsigned led);
|
||||||
void led_toggle(unsigned led);
|
void led_toggle(unsigned led);
|
||||||
|
|
||||||
// printf to USB
|
// printf to debug uart (or USB)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void uprintf(const char *fmt, ...);
|
void uprintf(const char *fmt, ...);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue