diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index 72437a3..2f54bad 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -70,7 +70,9 @@ inline void App_Init() { // Function will not return, the device will reboot with the new firmware instead // Firmware::PerformUpdate(&flash, fw_info); } - if(!FPGA::Configure(fw_info.FPGA_bitstream_address, fw_info.FPGA_bitstream_size)) { + // flash default FPGA image + auto fpga_info = Firmware::GetFPGAImageInfo(0); + if(!FPGA::Configure(fpga_info.start_address, fpga_info.size)) { LOG_CRIT("FPGA configuration failed"); LED::Error(3); } diff --git a/Software/VNA_embedded/Application/Cal.hpp b/Software/VNA_embedded/Application/Cal.hpp index d123c2b..7dd9216 100644 --- a/Software/VNA_embedded/Application/Cal.hpp +++ b/Software/VNA_embedded/Application/Cal.hpp @@ -11,6 +11,8 @@ constexpr uint8_t maxPoints = 64; constexpr uint32_t flash_address = Firmware::maxSize; // stored directly behind firmware in flash constexpr uint32_t flash_size = 8192; // reserve two sectors for now +static_assert(Firmware::maxSize + flash_size < Flash::FlashSize); + bool Load(); bool Save(); void SetDefault(); diff --git a/Software/VNA_embedded/Application/Drivers/Flash.hpp b/Software/VNA_embedded/Application/Drivers/Flash.hpp index d904290..cc489a9 100644 --- a/Software/VNA_embedded/Application/Drivers/Flash.hpp +++ b/Software/VNA_embedded/Application/Drivers/Flash.hpp @@ -33,6 +33,8 @@ public: static constexpr uint32_t Block32Size = 32768; static constexpr uint32_t Block64Size = 65536; + static constexpr uint32_t FlashSize = 2097152; + private: void CS(bool high) { if(high) { diff --git a/Software/VNA_embedded/Application/Firmware.cpp b/Software/VNA_embedded/Application/Firmware.cpp index 7732d42..387e065 100644 --- a/Software/VNA_embedded/Application/Firmware.cpp +++ b/Software/VNA_embedded/Application/Firmware.cpp @@ -8,21 +8,29 @@ #define LOG_MODULE "FW" #include "Log.h" -#define FPGA_MAXSIZE 512000 -#define CPU_MAXSIZE 131072 +static Firmware::FPGAImageInfo fpga_image_infos[FPGA_MAX_IMAGES]; +static uint8_t num_fpga_images; -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)); +static uint32_t calcCRCoverFlashMemory(uint32_t start, uint32_t size) { + uint32_t crc = UINT32_MAX; + uint8_t buf[128]; + uint32_t checked_size = 0; + while (checked_size < size) { + uint16_t read_size = sizeof(buf); + if (size - checked_size < read_size) { + read_size = size - checked_size; + } + HWHAL::flash.read(start + checked_size, read_size, buf); + crc = Protocol::CRC32(crc, buf, read_size); + checked_size += read_size; + } + return crc; +} Firmware::Info Firmware::GetFlashContentInfo() { Info ret; memset(&ret, 0, sizeof(ret)); + ret.num_FPGA_images = 1; Header h; HWHAL::flash.read(0, sizeof(h), &h); // sanity check values @@ -33,24 +41,13 @@ Firmware::Info Firmware::GetFlashContentInfo() { 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; - } - HWHAL::flash.read(h.FPGA_start + checked_size, read_size, buf); - crc = Protocol::CRC32(crc, buf, read_size); - checked_size += read_size; - } - if (crc != h.crc) { + if (calcCRCoverFlashMemory(h.FPGA_start, h.FPGA_size + h.CPU_size) != 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; + uint8_t buf[128]; + uint32_t checked_size = 0; while (checked_size < h.CPU_size) { uint16_t read_size = sizeof(buf); if (h.CPU_size - checked_size < read_size) { @@ -65,11 +62,45 @@ Firmware::Info Firmware::GetFlashContentInfo() { checked_size += read_size; } ret.valid = true; - ret.FPGA_bitstream_address = h.FPGA_start; - ret.FPGA_bitstream_size = h.FPGA_size; + fpga_image_infos[0].start_address = h.FPGA_start; + fpga_image_infos[0].size = h.FPGA_size; ret.CPU_image_address = h.CPU_start; ret.CPU_image_size = h.CPU_size; + // check if additional FPGA images are present + if(h.FPGA_start >= sizeof(Header) + sizeof(AdditionalFPGAImageHeader) + && h.CPU_start >= sizeof(Header) + sizeof(AdditionalFPGAImageHeader)) { + // there is enough room before the images for the additional image header + AdditionalFPGAImageHeader ah; + HWHAL::flash.read(sizeof(Header), sizeof(ah), &ah); + uint8_t additionalImages = 0; + // sanity check values + if (memcmp(&ah.magic, "VNA", 3) == 0) { + additionalImages = ah.additionalImages; + } + const uint32_t FPGAHeaderStart = sizeof(Header) + sizeof(AdditionalFPGAImageHeader); + for(auto i=0;i= UINT32_MAX || fh.size > FPGA_MAXSIZE) { + LOG_WARN("Ignoring additional FPGA image %d, implausible start/size", i); + continue; + } + // check CRC + if (calcCRCoverFlashMemory(fh.start, fh.size) != fh.crc) { + LOG_WARN("Ignoring additional FPGA image %d, CRC mismatch", i); + continue; + } + // add to available FPGA images + fpga_image_infos[ret.num_FPGA_images].start_address = fh.start; + fpga_image_infos[ret.num_FPGA_images].size = fh.size; + ret.num_FPGA_images++; + } + } + num_fpga_images = ret.num_FPGA_images; + LOG_INFO("FLASH evaluation finished, got %d FPGA images", ret.num_FPGA_images); + return ret; } @@ -159,6 +190,15 @@ static void copy_flash(uint32_t size, SPI_TypeDef *spi) { } } +Firmware::FPGAImageInfo Firmware::GetFPGAImageInfo(uint8_t image_num) { + if(image_num < num_fpga_images) { + return fpga_image_infos[image_num]; + } else { + FPGAImageInfo ret = {}; + return ret; + } +} + void Firmware::PerformUpdate(Info info) { if(!info.valid) { LOG_ERR("Invalid firmware data, not performing update"); diff --git a/Software/VNA_embedded/Application/Firmware.hpp b/Software/VNA_embedded/Application/Firmware.hpp index 5e62762..c0fe19f 100644 --- a/Software/VNA_embedded/Application/Firmware.hpp +++ b/Software/VNA_embedded/Application/Firmware.hpp @@ -12,17 +12,63 @@ namespace Firmware { -static constexpr uint32_t maxSize = 1048576; +#define FPGA_MAX_IMAGES 4 + +static constexpr uint32_t FPGA_MAXSIZE = 400000; +static constexpr uint32_t CPU_MAXSIZE = 131072; using Info = struct info { - uint32_t FPGA_bitstream_address; - uint32_t FPGA_bitstream_size; uint32_t CPU_image_address; uint32_t CPU_image_size; + uint8_t num_FPGA_images; bool valid; bool CPU_need_update; }; +using FPGAImageInfo = struct fpgaimageinfo { + uint32_t start_address; + uint32_t size; +}; + +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)); + +using AdditionalFPGAImageHeader = struct { + char magic[3]; + uint8_t additionalImages; +} __attribute__((packed)); + +using FPGAImageHeader = struct { + uint32_t start; + uint32_t size; + uint32_t crc; +} __attribute__((packed)); + +static constexpr uint32_t calcMaxSize() { + uint32_t max = sizeof(Header) + + sizeof(AdditionalFPGAImageHeader) + + sizeof(FPGAImageHeader)*FPGA_MAX_IMAGES + + FPGA_MAXSIZE*FPGA_MAX_IMAGES + + CPU_MAXSIZE; + // round up to next flash sector + if(max % Flash::SectorSize) { + max += Flash::SectorSize - max % Flash::SectorSize; + } + return max; +} + +static constexpr uint32_t maxSize = calcMaxSize(); + +static_assert(maxSize < Flash::FlashSize); + +FPGAImageInfo GetFPGAImageInfo(uint8_t image_num); + Info GetFlashContentInfo(); void PerformUpdate(Info info);