mirror of
https://github.com/jankae/LibreVNA.git
synced 2026-04-06 06:53:37 +00:00
Flash/FPGA driver for configuration and firmware update from uC
This commit is contained in:
parent
16f050a11e
commit
8c8749accd
20 changed files with 520 additions and 62 deletions
176
Software/VNA_embedded/Application/Firmware.cpp
Normal file
176
Software/VNA_embedded/Application/Firmware.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#include "Firmware.hpp"
|
||||
|
||||
#include "Protocol.hpp"
|
||||
#include <cstring>
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_INFO
|
||||
#define LOG_MODULE "FW"
|
||||
#include "Log.h"
|
||||
|
||||
#define FPGA_MAXSIZE 512000
|
||||
#define CPU_MAXSIZE 131072
|
||||
|
||||
using Header = struct {
|
||||
char magic[4];
|
||||
uint32_t FPGA_start;
|
||||
uint32_t FPGA_size;
|
||||
uint32_t CPU_start;
|
||||
uint32_t CPU_size;
|
||||
uint32_t crc;
|
||||
} __attribute__((packed));
|
||||
|
||||
Firmware::Info Firmware::GetFlashContentInfo(Flash *f) {
|
||||
Info ret;
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
Header h;
|
||||
f->read(0, sizeof(h), &h);
|
||||
// sanity check values
|
||||
if (memcmp(&h.magic, "VNA!",
|
||||
4) || h.FPGA_start == UINT32_MAX || h.FPGA_size > FPGA_MAXSIZE
|
||||
|| h.CPU_start == UINT32_MAX || h.CPU_size > CPU_MAXSIZE) {
|
||||
LOG_WARN("Invalid content, probably empty FLASH");
|
||||
return ret;
|
||||
}
|
||||
LOG_DEBUG("Checking FPGA bitstream...");
|
||||
uint32_t crc = UINT32_MAX;
|
||||
uint8_t buf[128];
|
||||
uint32_t checked_size = 0;
|
||||
while (checked_size < h.FPGA_size + h.CPU_size) {
|
||||
uint16_t read_size = sizeof(buf);
|
||||
if (h.FPGA_size + h.CPU_size - checked_size < read_size) {
|
||||
read_size = h.FPGA_size + h.CPU_size - checked_size;
|
||||
}
|
||||
f->read(h.FPGA_start + checked_size, read_size, buf);
|
||||
crc = Protocol::CRC32(crc, buf, read_size);
|
||||
}
|
||||
if (crc != h.crc) {
|
||||
LOG_ERR("CRC mismatch, invalid FPGA bitstream/CPU firmware");
|
||||
return ret;
|
||||
}
|
||||
// Compare CPU firmware in external Flash to the one currently running in the MCU
|
||||
checked_size = 0;
|
||||
while (checked_size < h.CPU_size) {
|
||||
uint16_t read_size = sizeof(buf);
|
||||
if (h.CPU_size - checked_size < read_size) {
|
||||
read_size = h.CPU_size - checked_size;
|
||||
}
|
||||
f->read(h.FPGA_start + checked_size, read_size, buf);
|
||||
if(memcmp(buf, (void*)(0x8000000+checked_size), read_size)) {
|
||||
LOG_WARN("Difference to CPU firmware in external FLASH detected, update required");
|
||||
ret.CPU_need_update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret.valid = true;
|
||||
ret.FPGA_bitstream_address = h.FPGA_start;
|
||||
ret.FPGA_bitstream_size = h.FPGA_size;
|
||||
ret.CPU_image_address = h.CPU_start;
|
||||
ret.CPU_image_size = h.CPU_size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void copy_flash(uint32_t size, SPI_TypeDef *spi) __attribute__ ((noinline, section (".data")));
|
||||
|
||||
/* This function is executed from RAM as it possibly overwrites the whole FLASH.
|
||||
*
|
||||
* It assumes that the flash has already be unlocked and the SPI interface to the
|
||||
* external flash has already initiated a read command. At the end of the copy
|
||||
* process it initiates a software reset.
|
||||
*
|
||||
* !NO FUNCTION CALLS AT ALL ARE ALLOWED IN HERE!
|
||||
*/
|
||||
static void copy_flash(uint32_t size, SPI_TypeDef *spi) {
|
||||
/* First, erase internal flash */
|
||||
/* disable caches */
|
||||
__HAL_FLASH_INSTRUCTION_CACHE_DISABLE();
|
||||
__HAL_FLASH_DATA_CACHE_DISABLE();
|
||||
/* Erase FLASH */
|
||||
// Erase the only flash bank
|
||||
SET_BIT(FLASH->CR, FLASH_CR_MER1);
|
||||
// Start erase process
|
||||
SET_BIT(FLASH->CR, FLASH_CR_STRT);
|
||||
// Wait for operation to finish
|
||||
while (FLASH->SR & FLASH_SR_BSY)
|
||||
;
|
||||
// Clear bank1 erase request
|
||||
CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1));
|
||||
|
||||
/* The complete FLASH has been erased. Copy the external FLASH memory
|
||||
* content into the internal MCU flash */
|
||||
uint32_t written = 0;
|
||||
|
||||
/* Enable FLASH write */
|
||||
FLASH->CR |= FLASH_CR_PG;
|
||||
uint32_t to = 0x80000000;
|
||||
while (written < size) {
|
||||
uint8_t buf[8];
|
||||
// Get 64bit from external flash
|
||||
for(uint8_t i=0;i<8;i++) {
|
||||
// wait for SPI ready to transmit dummy data
|
||||
while(!(spi->SR & SPI_FLAG_TXE));
|
||||
// send dummy byte
|
||||
*(__IO uint8_t *)spi->DR = 0x00;
|
||||
// wait for received byte to be ready
|
||||
while(!(spi->SR & SPI_FLAG_RXNE));
|
||||
// get received byte
|
||||
buf[i] = *(__IO uint8_t *)spi->DR;
|
||||
}
|
||||
// program received data into flash
|
||||
*(__IO uint32_t*) to++ = *(uint32_t*)&buf[0];
|
||||
*(__IO uint32_t*) to++ = *(uint32_t*)&buf[4];
|
||||
/* Wait for it to finish */
|
||||
while (FLASH->SR & FLASH_SR_BSY)
|
||||
;
|
||||
// clear possible error flags (there is no way to respond to errors at this point)
|
||||
uint32_t error = (FLASH->SR & FLASH_FLAG_SR_ERRORS);
|
||||
error |= (FLASH->ECCR & FLASH_FLAG_ECCD);
|
||||
if (error != 0u) {
|
||||
/* Clear error programming flags */
|
||||
__HAL_FLASH_CLEAR_FLAG(error);
|
||||
}
|
||||
/* Check FLASH End of Operation flag */
|
||||
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP)) {
|
||||
/* Clear FLASH End of Operation pending bit */
|
||||
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP);
|
||||
}
|
||||
written += 8;
|
||||
}
|
||||
/* Write operation completed, disable the PG Bit */
|
||||
FLASH->CR &= (~FLASH_CR_PG);
|
||||
|
||||
/* The new firmware is in place. This function can not return as the return
|
||||
* address might be anywhere in the new firmware. Instead perform a software reset
|
||||
* here */
|
||||
__DSB();
|
||||
SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
|
||||
SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
__DSB();
|
||||
|
||||
for (;;) {
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
void Firmware::PerformUpdate(Flash *f) {
|
||||
auto info = GetFlashContentInfo(f);
|
||||
if(!info.valid) {
|
||||
LOG_ERR("Invalid firmware data, not performing update");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Loading new firmware...");
|
||||
Log_Flush();
|
||||
|
||||
__disable_irq();
|
||||
|
||||
/* Flash must be unlocked */
|
||||
HAL_FLASH_Unlock();
|
||||
FLASH_WaitForLastOperation(50000);
|
||||
|
||||
// Initiate readback from flash at CPU firmware start address
|
||||
f->initiateRead(info.CPU_image_address);
|
||||
|
||||
copy_flash(info.CPU_image_size, f->getSpi()->Instance);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue