mirror of https://github.com/FOME-Tech/fome-fw.git
strip out dfu
This commit is contained in:
parent
a77ad48193
commit
cb37a3ef99
|
@ -191,11 +191,11 @@ CPPSRC = $(ALLCPPSRC) \
|
||||||
$(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \
|
$(PROJECT_DIR)/controllers/algo/engine_configuration.cpp \
|
||||||
$(PROJECT_DIR)/controllers/persistent_store.cpp \
|
$(PROJECT_DIR)/controllers/persistent_store.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/io_pins.cpp \
|
$(PROJECT_DIR)/hw_layer/io_pins.cpp \
|
||||||
|
$(PROJECT_DIR)/hw_layer/serial_over_usb/usbcfg.cpp \
|
||||||
$(PROJECT_DIR)/util/efilib.cpp \
|
$(PROJECT_DIR)/util/efilib.cpp \
|
||||||
$(PROJECT_DIR)/hw_layer/pin_repository.cpp \
|
$(PROJECT_DIR)/hw_layer/pin_repository.cpp \
|
||||||
$(RUSEFI_LIB_CPP) \
|
$(RUSEFI_LIB_CPP) \
|
||||||
src/rusefi_stubs.cpp \
|
src/rusefi_stubs.cpp \
|
||||||
src/dfu.cpp \
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
|
||||||
# C sources to be compiled in ARM mode regardless of the global setting.
|
# C sources to be compiled in ARM mode regardless of the global setting.
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
#include "pch.h"
|
|
||||||
|
|
||||||
#include "hardware.h"
|
|
||||||
|
|
||||||
#include "flash_int.h"
|
|
||||||
|
|
||||||
#include "dfu.h"
|
|
||||||
|
|
||||||
// Communication vars
|
|
||||||
static UartTsChannel blTsChannel(TS_PRIMARY_UxART_PORT);
|
|
||||||
static uint8_t buffer[DFU_BUFFER_SIZE];
|
|
||||||
// Use short timeout for the first data packet, and normal timeout for the rest
|
|
||||||
static int sr5Timeout = DFU_SR5_TIMEOUT_FIRST;
|
|
||||||
|
|
||||||
// This big buffer is used for temporary storing of the bootloader flash page
|
|
||||||
static uint8_t bootloaderVirtualPageBuffer[BOOTLOADER_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
// needed by DFU protocol (DFU_DEVICE_ID_CMD)
|
|
||||||
static uint32_t getMcuRevision() {
|
|
||||||
// =0x413 for F407
|
|
||||||
// =0x419 for F42xxx and F43xxx
|
|
||||||
// =0x434 for F469
|
|
||||||
return DBGMCU->IDCODE & MCU_REVISION_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool getByte(uint8_t *b) {
|
|
||||||
return blTsChannel.readTimeout(b, 1, sr5Timeout) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sendByte(uint8_t b) {
|
|
||||||
blTsChannel.write(&b, 1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t dfuCalcChecksum(const uint8_t *buf, uint8_t size) {
|
|
||||||
uint8_t checksum = buf[0];
|
|
||||||
|
|
||||||
for (uint8_t i = 1; i < size; i++) {
|
|
||||||
checksum ^= buf[i];
|
|
||||||
}
|
|
||||||
return checksum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to detect writing of the current flash sector
|
|
||||||
static bool isBootloaderAddress(uint32_t addr) {
|
|
||||||
return addr >= BOOTLOADER_ADDR && addr < (BOOTLOADER_ADDR + BOOTLOADER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isInVirtualPageBuffer(uint32_t addr) {
|
|
||||||
return addr >= (uint32_t)bootloaderVirtualPageBuffer && addr < (uint32_t)bootloaderVirtualPageBuffer + sizeof(bootloaderVirtualPageBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read 32-bit address and 8-bit checksum.
|
|
||||||
// Returns true if all 5 bytes are received and checksum is correct, and false otherwise.
|
|
||||||
static bool readAddress(uint32_t *addr) {
|
|
||||||
uint8_t buf[5]; // 4 bytes+checksum
|
|
||||||
if (blTsChannel.readTimeout(buf, 5, sr5Timeout) != 5)
|
|
||||||
return false;
|
|
||||||
if (dfuCalcChecksum(buf, 4) != buf[4])
|
|
||||||
return false;
|
|
||||||
*addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
|
||||||
|
|
||||||
// for bootloader flash, return a virtual buffer instead
|
|
||||||
if (isBootloaderAddress(*addr)) {
|
|
||||||
*addr = (uint32_t)bootloaderVirtualPageBuffer + (*addr - BOOTLOADER_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// needed by DFU protocol to validate received bytes
|
|
||||||
static uint8_t complementByte(uint8_t c) {
|
|
||||||
return c ^ 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t bufToInt16(uint8_t *buf) {
|
|
||||||
return (buf[0] << 8) | buf[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prepareInterruptsForJump() {
|
|
||||||
#ifdef STM32F4
|
|
||||||
// interrupt control
|
|
||||||
SCB->ICSR &= ~SCB_ICSR_PENDSVSET_Msk;
|
|
||||||
// set interrupt vectors
|
|
||||||
for(int i = 0; i < 8; i++)
|
|
||||||
NVIC->ICER[i] = NVIC->IABR[i];
|
|
||||||
__set_CONTROL(0);
|
|
||||||
#else
|
|
||||||
// todo: add support for other MCUs
|
|
||||||
#error "Unsupported MCU configuration!"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// some weird STM32 magic...
|
|
||||||
void dfuJumpToApp(uint32_t addr) {
|
|
||||||
typedef void (*pFunction)(void);
|
|
||||||
|
|
||||||
// goodbye ChibiOS, we're leaving...
|
|
||||||
chSysDisable();
|
|
||||||
|
|
||||||
// get jump addr
|
|
||||||
uint32_t jumpAddress = *((uint32_t *)(addr + 4));
|
|
||||||
pFunction jump = (pFunction) jumpAddress;
|
|
||||||
prepareInterruptsForJump();
|
|
||||||
// set stack pointer
|
|
||||||
__set_MSP(*(uint32_t *)addr);
|
|
||||||
|
|
||||||
// call
|
|
||||||
jump();
|
|
||||||
|
|
||||||
// we shouldn't get here
|
|
||||||
chSysHalt("dfuJumpToApp FAIL");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleGetList() {
|
|
||||||
static const uint8_t cmdsInfo[] = { DFU_VERSION_NUMBER, DFU_GET_LIST_CMD, DFU_DEVICE_ID_CMD, DFU_READ_CMD, DFU_GO_CMD,
|
|
||||||
DFU_WRITE_CMD, DFU_ERASE_CMD };
|
|
||||||
size_t numBytes = sizeof(cmdsInfo);
|
|
||||||
sendByte(numBytes - 1); // number of commands
|
|
||||||
for (size_t i = 0; i < numBytes; i++)
|
|
||||||
sendByte(cmdsInfo[i]);
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleDeviceId() {
|
|
||||||
uint32_t mcuRev = getMcuRevision();
|
|
||||||
sendByte(0x01); // the number of bytes to be send - 1
|
|
||||||
// send 12 bit MCU revision
|
|
||||||
sendByte((uint8_t)((mcuRev >> 8) & 0xf));
|
|
||||||
sendByte((uint8_t)(mcuRev & 0xff));
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleGo() {
|
|
||||||
uint32_t addr;
|
|
||||||
|
|
||||||
if (!readAddress(&addr)) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// todo: check if the address is valid
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
dfuJumpToApp(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleRead() {
|
|
||||||
uint32_t addr;
|
|
||||||
|
|
||||||
if (!readAddress(&addr)) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
uint8_t byte, complement;
|
|
||||||
if (!getByte(&byte))
|
|
||||||
return;
|
|
||||||
if (!getByte(&complement))
|
|
||||||
return;
|
|
||||||
// check if we have a correct byte received
|
|
||||||
if (complement != complementByte(byte)) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int numBytes = (int)byte + 1;
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
|
|
||||||
// read flash or virtual RAM buffer (don't transmit directly from flash)
|
|
||||||
if (isInVirtualPageBuffer(addr))
|
|
||||||
memcpy(buffer, (uint8_t *)addr, numBytes);
|
|
||||||
else
|
|
||||||
intFlashRead(addr, (char *)buffer, numBytes);
|
|
||||||
|
|
||||||
// transmit data
|
|
||||||
blTsChannel.write(buffer, numBytes, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleWrite() {
|
|
||||||
uint32_t addr;
|
|
||||||
|
|
||||||
if (!readAddress(&addr)) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
if (!getByte(buffer))
|
|
||||||
return;
|
|
||||||
|
|
||||||
int numBytes = buffer[0] + 1;
|
|
||||||
int numBytesAndChecksum = numBytes + 1; // +1 byte of checkSum
|
|
||||||
// receive data
|
|
||||||
if (blTsChannel.readTimeout(buffer + 1, numBytesAndChecksum, sr5Timeout) != numBytesAndChecksum)
|
|
||||||
return;
|
|
||||||
// don't write corrupted data!
|
|
||||||
if (dfuCalcChecksum(buffer, numBytesAndChecksum) != buffer[numBytesAndChecksum]) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now write to flash (or to the virtual RAM buffer)
|
|
||||||
if (isInVirtualPageBuffer(addr))
|
|
||||||
memcpy((uint8_t *)addr, (buffer + 1), numBytes);
|
|
||||||
else
|
|
||||||
intFlashWrite(addr, (const char *)(buffer + 1), numBytes);
|
|
||||||
|
|
||||||
// we're done!
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dfuHandleErase() {
|
|
||||||
int numSectors;
|
|
||||||
if (!getByte(buffer))
|
|
||||||
return;
|
|
||||||
if (!getByte(buffer + 1))
|
|
||||||
return;
|
|
||||||
numSectors = bufToInt16(buffer);
|
|
||||||
int numSectorData;
|
|
||||||
if (numSectors == 0xffff) // erase all chip
|
|
||||||
numSectorData = 1;
|
|
||||||
else
|
|
||||||
numSectorData = (numSectors + 1) * 2 + 1;
|
|
||||||
uint8_t *sectorList = buffer + 2;
|
|
||||||
// read sector data & checksum
|
|
||||||
if (blTsChannel.readTimeout(sectorList, numSectorData, sr5Timeout) != numSectorData)
|
|
||||||
return;
|
|
||||||
// verify checksum
|
|
||||||
if (dfuCalcChecksum(buffer, 2 + numSectorData - 1) != buffer[2 + numSectorData - 1]) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Erase the chosen sectors, sector by sector
|
|
||||||
for (int i = 0; i < numSectorData - 1; i += 2) {
|
|
||||||
int sectorIdx = bufToInt16(sectorList + i);
|
|
||||||
if (sectorIdx < BOOTLOADER_NUM_SECTORS) { // skip first sectors where our bootloader is
|
|
||||||
// imitate flash erase by writing '0xff'
|
|
||||||
memset(bootloaderVirtualPageBuffer, 0xff, BOOTLOADER_SIZE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// erase sector
|
|
||||||
intFlashSectorErase(sectorIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dfuStartLoop(void) {
|
|
||||||
bool wasCommand = false;
|
|
||||||
uint8_t command, complement;
|
|
||||||
|
|
||||||
sr5Timeout = DFU_SR5_TIMEOUT_FIRST;
|
|
||||||
|
|
||||||
// We cannot afford waiting for the first handshake byte, so we have to send an answer in advance!
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
|
|
||||||
// Fill the temporary buffer from the real flash memory
|
|
||||||
memcpy(bootloaderVirtualPageBuffer, (void *)BOOTLOADER_ADDR, BOOTLOADER_SIZE);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// read command & complement bytes
|
|
||||||
if (!getByte(&command)) {
|
|
||||||
// timeout, but wait more if we're in bootloader mode
|
|
||||||
if (wasCommand)
|
|
||||||
continue;
|
|
||||||
// exit if no data was received
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!getByte(&complement)) {
|
|
||||||
if (wasCommand) {
|
|
||||||
// something is wrong, but keep the connection
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we have a correct command received
|
|
||||||
if (complement != complementByte(command)) {
|
|
||||||
sendByte(DFU_NACK_BYTE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// confirm that we've got the command
|
|
||||||
sendByte(DFU_ACK_BYTE);
|
|
||||||
wasCommand = true;
|
|
||||||
// set normal (longer) timeout, we're not in a hurry anymore
|
|
||||||
sr5Timeout = DFU_SR5_TIMEOUT_NORMAL;
|
|
||||||
|
|
||||||
// now execute it (see ST appnote "AN3155")
|
|
||||||
switch (command) {
|
|
||||||
case DFU_UART_CHECK:
|
|
||||||
break;
|
|
||||||
case DFU_GET_LIST_CMD:
|
|
||||||
dfuHandleGetList();
|
|
||||||
break;
|
|
||||||
case DFU_DEVICE_ID_CMD:
|
|
||||||
dfuHandleDeviceId();
|
|
||||||
break;
|
|
||||||
case DFU_GO_CMD:
|
|
||||||
dfuHandleGo();
|
|
||||||
break;
|
|
||||||
case DFU_READ_CMD:
|
|
||||||
dfuHandleRead();
|
|
||||||
break;
|
|
||||||
case DFU_WRITE_CMD:
|
|
||||||
dfuHandleWrite();
|
|
||||||
break;
|
|
||||||
case DFU_ERASE_CMD:
|
|
||||||
dfuHandleErase();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
} /* End switch */
|
|
||||||
}
|
|
||||||
|
|
||||||
return wasCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerialTsChannelBase *getTsChannel() {
|
|
||||||
return &blTsChannel;
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tunerstudio_io.h"
|
|
||||||
|
|
||||||
// This is where the bootloader starts
|
|
||||||
#define BOOTLOADER_ADDR 0x08000000
|
|
||||||
// Bootloader code max. size, in bytes
|
|
||||||
#define BOOTLOADER_SIZE 0x8000
|
|
||||||
// Number of sectors for the bootloader
|
|
||||||
#define BOOTLOADER_NUM_SECTORS (BOOTLOADER_SIZE/0x4000)
|
|
||||||
|
|
||||||
// This is where the application starts
|
|
||||||
#define APPLICATION_ADDR 0x08008000
|
|
||||||
|
|
||||||
#define DFU_BUFFER_SIZE 258 // Max. 256 bytes at a time plus 2 bytes (numBytes+checksum)
|
|
||||||
|
|
||||||
|
|
||||||
// DFU/USART Protocol is described in AN3155 document "Application note. USART protocol used in the STM32 bootloader"
|
|
||||||
// http://www.st.com/resource/en/application_note/cd00264342.pdf
|
|
||||||
|
|
||||||
#define DFU_UART_CHECK 0x7F // "UART handshake" escape byte
|
|
||||||
|
|
||||||
#define DFU_GET_LIST_CMD 0x00 // "Get supported commands list" command
|
|
||||||
#define DFU_DEVICE_ID_CMD 0x02 // "Get device ID" command
|
|
||||||
#define DFU_READ_CMD 0x11 // "Read memory" command
|
|
||||||
#define DFU_GO_CMD 0x21 // "Go" command
|
|
||||||
#define DFU_WRITE_CMD 0x31 // "Write memory" command
|
|
||||||
#define DFU_ERASE_CMD 0x44 // "Erase memory" command
|
|
||||||
|
|
||||||
#define DFU_VERSION_NUMBER 0x31 // The DFU protocol version number
|
|
||||||
#define DFU_ACK_BYTE 0x79 // Acknowledge byte ID
|
|
||||||
#define DFU_NACK_BYTE 0x1F // Not-Acknowledge byte ID
|
|
||||||
|
|
||||||
#define DFU_SR5_TIMEOUT_FIRST TIME_MS2I(200)
|
|
||||||
#define DFU_SR5_TIMEOUT_NORMAL TIME_MS2I(1000)
|
|
||||||
|
|
||||||
#define MCU_REVISION_MASK 0xfff // MCU Revision ID is needed by DFU protocol
|
|
||||||
|
|
||||||
// The address in MCU system memory where the bootloader version number is stored (2 bytes)
|
|
||||||
#define DFU_BOOTLOADER_VERSION_ADDRESS 0x1FFF76DE
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function waits for the command to apply (write, read etc...)
|
|
||||||
*/
|
|
||||||
bool dfuStartLoop(void);
|
|
||||||
/**
|
|
||||||
* @brief Jump to the application
|
|
||||||
*/
|
|
||||||
void dfuJumpToApp(uint32_t addr);
|
|
||||||
|
|
||||||
SerialTsChannelBase* getTsChannel();
|
|
|
@ -3,38 +3,10 @@
|
||||||
|
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#include <ch.h>
|
|
||||||
#include <hal.h>
|
|
||||||
#include <stm32f4xx.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#include "dfu.h"
|
|
||||||
|
|
||||||
static bool wasCommand = false;
|
|
||||||
|
|
||||||
static THD_WORKING_AREA(waBootloaderSerial, 128);
|
|
||||||
static THD_FUNCTION(thBootloaderSerial, arg) {
|
|
||||||
(void)arg;
|
|
||||||
chRegSetThreadName("BootloaderSerial");
|
|
||||||
|
|
||||||
// start our DFU emulator
|
|
||||||
wasCommand = dfuStartLoop();
|
|
||||||
|
|
||||||
chThdExit(MSG_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// run ChibiOS
|
|
||||||
halInit();
|
halInit();
|
||||||
chSysInit();
|
chSysInit();
|
||||||
|
|
||||||
// set base pin configuration based on the board
|
// set base pin configuration based on the board
|
||||||
setDefaultBasePins();
|
setDefaultBasePins();
|
||||||
/* at the moment SD card is not needed by bootloader
|
/* at the moment SD card is not needed by bootloader
|
||||||
|
@ -42,23 +14,7 @@ int main(void) {
|
||||||
setDefaultSdCardParameters();
|
setDefaultSdCardParameters();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// start UART
|
while (true) {
|
||||||
getTsChannel()->start(38400); // TODO: should bootloader serial speed be configurable?
|
chThdSleepMilliseconds(1);
|
||||||
|
}
|
||||||
// start a serial port reader thread
|
|
||||||
thread_t *thrSerial = chThdCreateStatic(waBootloaderSerial, sizeof(waBootloaderSerial), NORMALPRIO, thBootloaderSerial, NULL);
|
|
||||||
|
|
||||||
// wait for the thread to finish
|
|
||||||
chThdWait(thrSerial);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (wasCommand) // abnormal termination of the bootloader thread
|
|
||||||
chSysHalt("Bootloader DFU FAIL");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Run application
|
|
||||||
dfuJumpToApp(APPLICATION_ADDR);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue