diff --git a/Software/VNA_embedded/.cproject b/Software/VNA_embedded/.cproject index 486deae..ed61843 100644 --- a/Software/VNA_embedded/.cproject +++ b/Software/VNA_embedded/.cproject @@ -151,6 +151,8 @@ + + @@ -185,6 +187,8 @@ + + diff --git a/Software/VNA_embedded/Application/App.cpp b/Software/VNA_embedded/Application/App.cpp index c8d9602..6e09120 100644 --- a/Software/VNA_embedded/Application/App.cpp +++ b/Software/VNA_embedded/Application/App.cpp @@ -5,12 +5,11 @@ #include "Communication.h" #include "main.h" #include "Exti.hpp" -#include "FPGA.hpp" +#include "FPGA/FPGA.hpp" #include #include #include "USB/usb.h" #include "Flash.hpp" -#include "Firmware.hpp" #include "FreeRTOS.h" #include "task.h" @@ -28,12 +27,17 @@ static Protocol::PacketInfo packet; static TaskHandle_t handle; // TODO set proper values -#define HW_REVISION 'A' +//#define HW_REVISION 'A' #define FW_MAJOR 0 #define FW_MINOR 01 +#if HW_REVISION >= 'B' +// has MCU controllable flash chip, firmware update supported +#define HAS_FLASH +#include "Firmware.hpp" extern SPI_HandleTypeDef hspi1; static Flash flash = Flash(&hspi1, FLASH_CS_GPIO_Port, FLASH_CS_Pin); +#endif #define FLAG_USB_PACKET 0x01 #define FLAG_DATAPOINT 0x02 @@ -67,6 +71,7 @@ void App_Start() { Log_SetRedirect(usb_log); LOG_INFO("Start"); Exti::Init(); +#ifdef HAS_FLASH if(!flash.isPresent()) { LOG_CRIT("Failed to detect onboard FLASH"); } @@ -80,10 +85,19 @@ void App_Start() { } else { LOG_CRIT("Invalid bitstream/firmware, not configuring FPGA"); } +#else + // The FPGA configures itself from the flash, allow time for this + vTaskDelay(2000); +#endif if (!VNA::Init()) { LOG_CRIT("Initialization failed, unable to start"); } +#if HW_REVISION == 'A' + // Allow USB enumeration + USB_EN_GPIO_Port->BSRR = USB_EN_Pin; +#endif + uint32_t lastNewPoint = HAL_GetTick(); bool sweepActive = false; @@ -180,25 +194,23 @@ void App_Start() { manual = packet.manual; VNA::ConfigureManual(manual, VNAStatusCallback); break; +#ifdef HAS_FLASH case Protocol::PacketType::ClearFlash: FPGA::AbortSweep(); sweepActive = false; LOG_DEBUG("Erasing FLASH in preparation for firmware update..."); if(flash.eraseChip()) { LOG_DEBUG("...FLASH erased") - Protocol::PacketInfo p; - p.type = Protocol::PacketType::Ack; - Communication::Send(p); + Communication::SendWithoutPayload(Protocol::PacketType::Ack); } else { LOG_ERR("Failed to erase FLASH"); + Communication::SendWithoutPayload(Protocol::PacketType::Nack); } break; case Protocol::PacketType::FirmwarePacket: LOG_INFO("Writing firmware packet at address %u", packet.firmware.address); flash.write(packet.firmware.address, sizeof(packet.firmware.data), packet.firmware.data); - Protocol::PacketInfo p; - p.type = Protocol::PacketType::Ack; - Communication::Send(p); + Communication::SendWithoutPayload(Protocol::PacketType::Ack); break; case Protocol::PacketType::PerformFirmwareUpdate: { auto fw_info = Firmware::GetFlashContentInfo(&flash); @@ -209,12 +221,15 @@ void App_Start() { // Some delay to allow communication to finish vTaskDelay(1000); Firmware::PerformUpdate(&flash); - // will never get here + // should never get here + Communication::SendWithoutPayload(Protocol::PacketType::Nack); } } break; +#endif default: - // ignore all other packets + // this packet type is not supported + Communication::SendWithoutPayload(Protocol::PacketType::Nack); break; } } diff --git a/Software/VNA_embedded/Application/Communication/Communication.cpp b/Software/VNA_embedded/Application/Communication/Communication.cpp index 9b9b64e..0fb7122 100644 --- a/Software/VNA_embedded/Application/Communication/Communication.cpp +++ b/Software/VNA_embedded/Application/Communication/Communication.cpp @@ -63,3 +63,8 @@ void communication_usb_input(const uint8_t *buf, uint16_t len) { Communication::Input(buf, len); } +bool Communication::SendWithoutPayload(Protocol::PacketType type) { + Protocol::PacketInfo p; + p.type = type; + return Send(p); +} diff --git a/Software/VNA_embedded/Application/Communication/Communication.h b/Software/VNA_embedded/Application/Communication/Communication.h index d7fbd4d..1db380c 100644 --- a/Software/VNA_embedded/Application/Communication/Communication.h +++ b/Software/VNA_embedded/Application/Communication/Communication.h @@ -13,6 +13,7 @@ using Callback = void(*)(Protocol::PacketInfo); void SetCallback(Callback cb); void Input(const uint8_t *buf, uint16_t len); bool Send(Protocol::PacketInfo packet); +bool SendWithoutPayload(Protocol::PacketType type); } diff --git a/Software/VNA_embedded/Application/Communication/Protocol.hpp b/Software/VNA_embedded/Application/Communication/Protocol.hpp index f30449b..6d62027 100644 --- a/Software/VNA_embedded/Application/Communication/Protocol.hpp +++ b/Software/VNA_embedded/Application/Communication/Protocol.hpp @@ -101,6 +101,7 @@ enum class PacketType : uint8_t { Ack = 7, ClearFlash = 8, PerformFirmwareUpdate = 9, + Nack = 10, }; using PacketInfo = struct _packetinfo { diff --git a/Software/VNA_embedded/Application/Drivers/Exti.cpp b/Software/VNA_embedded/Application/Drivers/Exti.cpp index 5f57e90..204713f 100644 --- a/Software/VNA_embedded/Application/Drivers/Exti.cpp +++ b/Software/VNA_embedded/Application/Drivers/Exti.cpp @@ -11,13 +11,13 @@ static constexpr uint8_t MaxEntries = 16; static Entry entries[MaxEntries]; void Exti::Init() { - HAL_NVIC_SetPriority(EXTI0_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI2_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI3_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI4_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI9_5_IRQn, 1, 0); - HAL_NVIC_SetPriority(EXTI15_10_IRQn, 1, 0); + HAL_NVIC_SetPriority(EXTI0_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI1_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI3_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI4_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0); + HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); HAL_NVIC_EnableIRQ(EXTI1_IRQn); HAL_NVIC_EnableIRQ(EXTI2_IRQn); diff --git a/Software/VNA_embedded/Application/Drivers/FPGA.cpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp similarity index 88% rename from Software/VNA_embedded/Application/Drivers/FPGA.cpp rename to Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp index 14d6179..4ee7ef8 100644 --- a/Software/VNA_embedded/Application/Drivers/FPGA.cpp +++ b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.cpp @@ -2,42 +2,18 @@ #include "delay.hpp" #include "stm.hpp" #include "main.h" +#include "FPGA_HAL.hpp" #define LOG_LEVEL LOG_LEVEL_DEBUG #define LOG_MODULE "FPGA" #include "Log.h" -#define FPGA_SPI hspi1 -#define CONFIGURATION_SPI hspi2 -extern SPI_HandleTypeDef FPGA_SPI, CONFIGURATION_SPI; - -using GPIO = struct { - GPIO_TypeDef *gpio; - uint16_t pin; -}; -static constexpr GPIO CS = {.gpio = FPGA_CS_GPIO_Port, .pin = FPGA_CS_Pin}; -static constexpr GPIO PROGRAM_B = {.gpio = FPGA_PROGRAM_B_GPIO_Port, .pin = FPGA_PROGRAM_B_Pin}; -static constexpr GPIO INIT_B = {.gpio = FPGA_INIT_B_GPIO_Port, .pin = FPGA_INIT_B_Pin}; -static constexpr GPIO DONE = {.gpio = FPGA_DONE_GPIO_Port, .pin = FPGA_DONE_Pin}; -static constexpr GPIO FPGA_RESET = {.gpio = FPGA_RESET_GPIO_Port, .pin = FPGA_RESET_Pin}; -static constexpr GPIO AUX1 = {.gpio = FPGA_AUX1_GPIO_Port, .pin = FPGA_AUX1_Pin}; -static constexpr GPIO AUX2 = {.gpio = FPGA_AUX2_GPIO_Port, .pin = FPGA_AUX2_Pin}; -static constexpr GPIO AUX3 = {.gpio = FPGA_AUX3_GPIO_Port, .pin = FPGA_AUX3_Pin}; - -static inline void Low(GPIO g) { - g.gpio->BSRR = g.pin << 16; -} -static inline void High(GPIO g) { - g.gpio->BSRR = g.pin; -} -bool isHigh(GPIO g) { - return g.gpio->IDR & g.pin; -} - static FPGA::HaltedCallback halted_cb; static uint16_t SysCtrlReg = 0x0000; static uint16_t ISRMaskReg = 0x0000; +using namespace FPGAHAL; + void WriteRegister(FPGA::Reg reg, uint16_t value) { uint16_t cmd[2] = {(uint16_t) (0x8000 | (uint16_t) reg), value}; Low(CS); @@ -46,6 +22,12 @@ void WriteRegister(FPGA::Reg reg, uint16_t value) { } bool FPGA::Configure(Flash *f, uint32_t start_address, uint32_t bitstream_size) { + if(!PROGRAM_B.gpio) { + LOG_WARN("PROGRAM_B not defined, assuming FPGA configures itself in master configuration"); + // wait too allow enough time for FPGA configuration + HAL_Delay(2000); + return true; + } LOG_INFO("Loading bitstream of size %lu...", bitstream_size); Low(PROGRAM_B); while(isHigh(INIT_B)); diff --git a/Software/VNA_embedded/Application/Drivers/FPGA.hpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp similarity index 100% rename from Software/VNA_embedded/Application/Drivers/FPGA.hpp rename to Software/VNA_embedded/Application/Drivers/FPGA/FPGA.hpp diff --git a/Software/VNA_embedded/Application/Drivers/FPGA/FPGA_HAL.hpp b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA_HAL.hpp new file mode 100644 index 0000000..87196a1 --- /dev/null +++ b/Software/VNA_embedded/Application/Drivers/FPGA/FPGA_HAL.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "stm.hpp" +#include "main.h" + +#define FPGA_SPI hspi1 +#define CONFIGURATION_SPI hspi2 +extern SPI_HandleTypeDef FPGA_SPI, CONFIGURATION_SPI; + +namespace FPGAHAL { + +using GPIO = struct { + GPIO_TypeDef *gpio; + uint16_t pin; +}; +static constexpr GPIO CS = {.gpio = FPGA_CS_GPIO_Port, .pin = FPGA_CS_Pin}; +static constexpr GPIO PROGRAM_B = {.gpio = FPGA_PROGRAM_B_GPIO_Port, .pin = FPGA_PROGRAM_B_Pin}; +static constexpr GPIO INIT_B = {.gpio = FPGA_INIT_B_GPIO_Port, .pin = FPGA_INIT_B_Pin}; +static constexpr GPIO DONE = {.gpio = FPGA_DONE_GPIO_Port, .pin = FPGA_DONE_Pin}; +static constexpr GPIO FPGA_RESET = {.gpio = FPGA_RESET_GPIO_Port, .pin = FPGA_RESET_Pin}; +static constexpr GPIO AUX1 = {.gpio = FPGA_AUX1_GPIO_Port, .pin = FPGA_AUX1_Pin}; +static constexpr GPIO AUX2 = {.gpio = FPGA_AUX2_GPIO_Port, .pin = FPGA_AUX2_Pin}; +static constexpr GPIO AUX3 = {.gpio = FPGA_AUX3_GPIO_Port, .pin = FPGA_AUX3_Pin}; + +static inline void Low(GPIO g) { + if(g.gpio) { + g.gpio->BSRR = g.pin << 16; + } +} +static inline void High(GPIO g) { + if(g.gpio) { + g.gpio->BSRR = g.pin; + } +} +bool isHigh(GPIO g) { + if(g.gpio) { + return g.gpio->IDR & g.pin; + } else { + return false; + } +} + +} diff --git a/Software/VNA_embedded/Application/VNA.cpp b/Software/VNA_embedded/Application/VNA.cpp index 02edfee..2ebda5f 100644 --- a/Software/VNA_embedded/Application/VNA.cpp +++ b/Software/VNA_embedded/Application/VNA.cpp @@ -3,21 +3,15 @@ #include "max2871.hpp" #include "main.h" #include "delay.hpp" -#include "FPGA.hpp" +#include "FPGA/FPGA.hpp" #include #include "Exti.hpp" +#include "VNA_HAL.hpp" #define LOG_LEVEL LOG_LEVEL_INFO #define LOG_MODULE "VNA" #include "Log.h" -extern I2C_HandleTypeDef hi2c2; -extern SPI_HandleTypeDef hspi1; - -static Si5351C Si5351 = Si5351C(&hi2c2, 26000000); -static MAX2871 Source = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOB, GPIO_PIN_4); -static MAX2871 LO1 = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOB, GPIO_PIN_4); - static constexpr uint32_t IF1 = 60100000; static constexpr uint32_t IF1_alternate = 57000000; static constexpr uint32_t IF2 = 250000; @@ -42,6 +36,8 @@ static uint16_t IFTableIndexCnt = 0; static constexpr uint32_t BandSwitchFrequency = 25000000; +using namespace VNAHAL; + static void HaltedCallback() { LOG_DEBUG("Halted before point %d", pointCnt); // Check if IF table has entry at this point @@ -59,16 +55,16 @@ static void HaltedCallback() { / (settings.points - 1); if (frequency < BandSwitchFrequency) { // need the Si5351 as Source - Si5351.SetCLK(0, frequency, Si5351C::PLL::B, + Si5351.SetCLK(SiChannel::LowbandSource, frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); if (pointCnt == 0) { // First point in sweep, enable CLK - Si5351.Enable(0); + Si5351.Enable(SiChannel::LowbandSource); FPGA::Disable(FPGA::Periphery::SourceRF); } } else { // first sweep point in highband is also halted, disable lowband source - Si5351.Disable(0); + Si5351.Disable(SiChannel::LowbandSource); FPGA::Enable(FPGA::Periphery::SourceRF); } @@ -122,8 +118,6 @@ static void FPGA_Interrupt(void*) { bool VNA::Init() { LOG_DEBUG("Initializing..."); - // Wait for FPGA to finish configuration - Delay::ms(2000); manualMode = false; Si5351.Init(); @@ -136,24 +130,25 @@ bool VNA::Init() { while(!Si5351.Locked(Si5351C::PLL::B)); // Both MAX2871 get a 100MHz reference - Si5351.SetCLK(2, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); - Si5351.Enable(2); - Si5351.SetCLK(3, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); - Si5351.Enable(3); + Si5351.SetCLK(SiChannel::Source, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::Source); + Si5351.SetCLK(SiChannel::LO1, 100000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::LO1); // 16MHz FPGA clock - Si5351.SetCLK(7, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); - Si5351.Enable(7); - // 10 MHz external reference clock - Si5351.SetCLK(6, 10000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA8); - Si5351.Enable(6); + Si5351.SetCLK(SiChannel::FPGA, 16000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::FPGA); + // TODO reference settings controllable through USB +// // 10 MHz external reference clock +// Si5351.SetCLK(6, 10000000, Si5351C::PLL::A, Si5351C::DriveStrength::mA8); +// Si5351.Enable(6); // Generate second LO with Si5351 - Si5351.SetCLK(1, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(1); - Si5351.SetCLK(4, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(4); - Si5351.SetCLK(5, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(5); + Si5351.SetCLK(SiChannel::Port1LO2, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::Port1LO2); + Si5351.SetCLK(SiChannel::Port2LO2, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::Port2LO2); + Si5351.SetCLK(SiChannel::RefLO2, IF1 - IF2, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::RefLO2); // PLL reset appears to realign phases of clock signals Si5351.ResetPLL(Si5351C::PLL::B); @@ -301,7 +296,7 @@ bool VNA::ConfigureSweep(Protocol::SweepSettings s, SweepCallback cb) { IFTable[IFTableIndexCnt].IF1 = used_IF; // Configure LO2 for the changed IF1. This is not necessary right now but it will generate // the correct clock settings - Si5351.SetCLK(1, used_IF + IF2, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); + Si5351.SetCLK(SiChannel::RefLO2, used_IF + IF2, Si5351C::PLL::A, Si5351C::DriveStrength::mA2); // store calculated clock configuration for later change Si5351.ReadRawCLKConfig(1, IFTable[IFTableIndexCnt].clkconfig); IFTableIndexCnt++; @@ -349,11 +344,11 @@ bool VNA::ConfigureManual(Protocol::ManualControl m, StatusCallback cb) { FPGA::AbortSweep(); // Configure lowband source if (m.SourceLowEN) { - Si5351.SetCLK(0, m.SourceLowFrequency, Si5351C::PLL::B, + Si5351.SetCLK(SiChannel::LowbandSource, m.SourceLowFrequency, Si5351C::PLL::B, (Si5351C::DriveStrength) m.SourceLowPower); - Si5351.Enable(0); + Si5351.Enable(SiChannel::LowbandSource); } else { - Si5351.Disable(0); + Si5351.Disable(SiChannel::LowbandSource); } // Configure highband source Source.SetFrequency(m.SourceHighFrequency); @@ -365,19 +360,19 @@ bool VNA::ConfigureManual(Protocol::ManualControl m, StatusCallback cb) { // Configure LO2 if(m.LO2EN) { // Generate second LO with Si5351 - Si5351.SetCLK(1, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(1); - Si5351.SetCLK(4, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(4); - Si5351.SetCLK(5, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); - Si5351.Enable(5); + Si5351.SetCLK(SiChannel::Port1LO2, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::Port1LO2); + Si5351.SetCLK(SiChannel::Port2LO2, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::Port2LO2); + Si5351.SetCLK(SiChannel::RefLO2, m.LO2Frequency, Si5351C::PLL::B, Si5351C::DriveStrength::mA2); + Si5351.Enable(SiChannel::RefLO2); // PLL reset appears to realign phases of clock signals Si5351.ResetPLL(Si5351C::PLL::B); } else { - Si5351.Disable(1); - Si5351.Disable(4); - Si5351.Disable(5); + Si5351.Disable(SiChannel::Port1LO2); + Si5351.Disable(SiChannel::Port2LO2); + Si5351.Disable(SiChannel::RefLO2); } FPGA::WriteMAX2871Default(Source.GetRegisters()); diff --git a/Software/VNA_embedded/Application/VNA.hpp b/Software/VNA_embedded/Application/VNA.hpp index 6b65e95..74d379f 100644 --- a/Software/VNA_embedded/Application/VNA.hpp +++ b/Software/VNA_embedded/Application/VNA.hpp @@ -2,7 +2,7 @@ #include #include "Protocol.hpp" -#include "FPGA.hpp" +#include "FPGA/FPGA.hpp" namespace VNA { diff --git a/Software/VNA_embedded/Application/VNA_HAL.hpp b/Software/VNA_embedded/Application/VNA_HAL.hpp new file mode 100644 index 0000000..6e3d0fa --- /dev/null +++ b/Software/VNA_embedded/Application/VNA_HAL.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "stm.hpp" +#include "Si5351C.hpp" +#include "max2871.hpp" +#include "main.h" + +extern I2C_HandleTypeDef hi2c2; +extern SPI_HandleTypeDef hspi1; + +namespace VNAHAL { + +static Si5351C Si5351 = Si5351C(&hi2c2, 26000000); +static MAX2871 Source = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOB, GPIO_PIN_4); +static MAX2871 LO1 = MAX2871(&hspi1, FPGA_CS_GPIO_Port, FPGA_CS_Pin, nullptr, 0, nullptr, 0, nullptr, 0, GPIOB, GPIO_PIN_4); + +// Mapping of the Si5351 channels to PLLs/Mixers +namespace SiChannel { + enum { + Source = 3, + LO1 = 5, + Port2LO2 = 4, + RefLO2 = 1, + Port1LO2 = 2, + LowbandSource = 1, + ReferenceOut = 6, + FPGA = 7, + }; +} + +}