mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-09-14 10:39:30 +00:00
praline without the much fixed ram (#3123)
This commit is contained in:
@@ -636,7 +636,7 @@ init_status_t init() {
|
|||||||
// This function returns LD_SUCCESS (0) if the FPGA confirms the bitstream
|
// This function returns LD_SUCCESS (0) if the FPGA confirms the bitstream
|
||||||
// Call fpga_bridge_init and continue boot regardless of result
|
// Call fpga_bridge_init and continue boot regardless of result
|
||||||
// (Watchdog was resetting device when we halted with while(1))
|
// (Watchdog was resetting device when we halted with while(1))
|
||||||
int load_result = fpga_bridge_init();
|
int load_result = fpga_bridge_init(&shared_memory.bb_data.data[0]);
|
||||||
(void)load_result; // Ignore result for now, just let boot continue
|
(void)load_result; // Ignore result for now, just let boot continue
|
||||||
|
|
||||||
/* RELEASE FPGA RESET */
|
/* RELEASE FPGA RESET */
|
||||||
|
|||||||
@@ -3,185 +3,187 @@
|
|||||||
|
|
||||||
// Check if PRALINE was passed from CMake
|
// Check if PRALINE was passed from CMake
|
||||||
#ifdef PRALINE
|
#ifdef PRALINE
|
||||||
#include "fpga_bridge.h"
|
#include "fpga_bridge.h"
|
||||||
|
|
||||||
// Necessary headers
|
// Necessary headers
|
||||||
#include "lz4_blk.h"
|
#include "lz4_blk.h"
|
||||||
|
|
||||||
// LIBOPENCM3 Headers (only CGU for clock setup)
|
// LIBOPENCM3 Headers (only CGU for clock setup)
|
||||||
#include <libopencm3/lpc43xx/cgu.h>
|
#include <libopencm3/lpc43xx/cgu.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
// SPIFI memory-mapped base address
|
// SPIFI memory-mapped base address
|
||||||
// Flash is mapped starting at 0x14000000
|
// Flash is mapped starting at 0x14000000
|
||||||
// FPGA bitstream at flash address 0x380000 = memory address 0x14380000
|
// FPGA bitstream at flash address 0x380000 = memory address 0x14380000
|
||||||
// PRALINE: Moved to 1.5MB offset to allow larger base firmware
|
// PRALINE: Moved to 1.5MB offset to allow larger base firmware
|
||||||
#define SPIFI_DATA_BASE 0x14000000
|
#define SPIFI_DATA_BASE 0x14000000
|
||||||
#define FPGA_BITSTREAM_FLASH_ADDR 0x380000 // Was 0x100000 (1MB), then 0x180000 (1.5MB), now 0x380000 (3.5MB)
|
#define FPGA_BITSTREAM_FLASH_ADDR 0x380000 // Was 0x100000 (1MB), then 0x180000 (1.5MB), now 0x380000 (3.5MB)
|
||||||
#define FPGA_BITSTREAM_MEM_ADDR (SPIFI_DATA_BASE + FPGA_BITSTREAM_FLASH_ADDR)
|
#define FPGA_BITSTREAM_MEM_ADDR (SPIFI_DATA_BASE + FPGA_BITSTREAM_FLASH_ADDR)
|
||||||
|
|
||||||
// MMIO32 direct register access
|
// MMIO32 direct register access
|
||||||
#define MMIO32_LOCAL(addr) (*(volatile uint32_t*)(addr))
|
#define MMIO32_LOCAL(addr) (*(volatile uint32_t*)(addr))
|
||||||
|
|
||||||
// SSP1 base address
|
// SSP1 base address
|
||||||
#define SSP1_BASE_LOCAL 0x400C5000
|
#define SSP1_BASE_LOCAL 0x400C5000
|
||||||
|
|
||||||
// SSP register offsets
|
// SSP register offsets
|
||||||
#define SSP_CR0_OFF 0x000
|
#define SSP_CR0_OFF 0x000
|
||||||
#define SSP_CR1_OFF 0x004
|
#define SSP_CR1_OFF 0x004
|
||||||
#define SSP_DR_OFF 0x008
|
#define SSP_DR_OFF 0x008
|
||||||
#define SSP_SR_OFF 0x00C
|
#define SSP_SR_OFF 0x00C
|
||||||
#define SSP_CPSR_OFF 0x010
|
#define SSP_CPSR_OFF 0x010
|
||||||
|
|
||||||
// SSP register access
|
// SSP register access
|
||||||
#define SSP1_CR0_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CR0_OFF)
|
#define SSP1_CR0_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CR0_OFF)
|
||||||
#define SSP1_CR1_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CR1_OFF)
|
#define SSP1_CR1_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CR1_OFF)
|
||||||
#define SSP1_DR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_DR_OFF)
|
#define SSP1_DR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_DR_OFF)
|
||||||
#define SSP1_SR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_SR_OFF)
|
#define SSP1_SR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_SR_OFF)
|
||||||
#define SSP1_CPSR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CPSR_OFF)
|
#define SSP1_CPSR_LOCAL MMIO32_LOCAL(SSP1_BASE_LOCAL + SSP_CPSR_OFF)
|
||||||
|
|
||||||
// SSP status bits
|
// SSP status bits
|
||||||
#define SSP_SR_TNF_LOCAL (1 << 1) // TX FIFO not full
|
#define SSP_SR_TNF_LOCAL (1 << 1) // TX FIFO not full
|
||||||
#define SSP_SR_RNE_LOCAL (1 << 2) // RX FIFO not empty
|
#define SSP_SR_RNE_LOCAL (1 << 2) // RX FIFO not empty
|
||||||
#define SSP_SR_BSY_LOCAL (1 << 4) // Busy
|
#define SSP_SR_BSY_LOCAL (1 << 4) // Busy
|
||||||
|
|
||||||
// SSP CR0 bits
|
// SSP CR0 bits
|
||||||
#define SSP_CR0_DSS_8BIT (0x7) // 8-bit data
|
#define SSP_CR0_DSS_8BIT (0x7) // 8-bit data
|
||||||
#define SSP_CR0_FRF_SPI (0x0) // SPI frame format
|
#define SSP_CR0_FRF_SPI (0x0) // SPI frame format
|
||||||
#define SSP_CR0_CPOL (1 << 6) // Clock polarity
|
#define SSP_CR0_CPOL (1 << 6) // Clock polarity
|
||||||
#define SSP_CR0_CPHA (1 << 7) // Clock phase
|
#define SSP_CR0_CPHA (1 << 7) // Clock phase
|
||||||
|
|
||||||
// SSP CR1 bits
|
// SSP CR1 bits
|
||||||
#define SSP_CR1_SSE (1 << 1) // SSP enable
|
#define SSP_CR1_SSE (1 << 1) // SSP enable
|
||||||
|
|
||||||
// SCU pin configuration registers
|
// SCU pin configuration registers
|
||||||
#define PERIPH_BASE_APB0_LOCAL 0x40080000
|
#define PERIPH_BASE_APB0_LOCAL 0x40080000
|
||||||
#define SCU_BASE_LOCAL (PERIPH_BASE_APB0_LOCAL + 0x06000)
|
#define SCU_BASE_LOCAL (PERIPH_BASE_APB0_LOCAL + 0x06000)
|
||||||
#define PIN_GROUP1_LOCAL (SCU_BASE_LOCAL + 0x080)
|
#define PIN_GROUP1_LOCAL (SCU_BASE_LOCAL + 0x080)
|
||||||
#define PIN_GROUP4_LOCAL (SCU_BASE_LOCAL + 0x200)
|
#define PIN_GROUP4_LOCAL (SCU_BASE_LOCAL + 0x200)
|
||||||
#define PIN_GROUP5_LOCAL (SCU_BASE_LOCAL + 0x280)
|
#define PIN_GROUP5_LOCAL (SCU_BASE_LOCAL + 0x280)
|
||||||
#define PIN3_LOCAL 0x00C
|
#define PIN3_LOCAL 0x00C
|
||||||
#define PIN4_LOCAL 0x010
|
#define PIN4_LOCAL 0x010
|
||||||
#define PIN1_LOCAL 0x004
|
#define PIN1_LOCAL 0x004
|
||||||
#define PIN2_LOCAL 0x008
|
#define PIN2_LOCAL 0x008
|
||||||
#define PIN10_LOCAL 0x028
|
#define PIN10_LOCAL 0x028
|
||||||
#define PIN19_LOCAL 0x04C
|
#define PIN19_LOCAL 0x04C
|
||||||
|
|
||||||
// SCU configuration flags
|
// SCU configuration flags
|
||||||
#define SCU_CONF_EPUN_DIS_PULLUP_LOCAL (1 << 4)
|
#define SCU_CONF_EPUN_DIS_PULLUP_LOCAL (1 << 4)
|
||||||
#define SCU_CONF_EHS_FAST_LOCAL (1 << 5)
|
#define SCU_CONF_EHS_FAST_LOCAL (1 << 5)
|
||||||
#define SCU_CONF_EZI_EN_IN_BUFFER_LOCAL (1 << 6)
|
#define SCU_CONF_EZI_EN_IN_BUFFER_LOCAL (1 << 6)
|
||||||
#define SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL (1 << 7)
|
#define SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL (1 << 7)
|
||||||
#define SCU_GPIO_FAST_LOCAL (SCU_CONF_EPUN_DIS_PULLUP_LOCAL | \
|
#define SCU_GPIO_FAST_LOCAL (SCU_CONF_EPUN_DIS_PULLUP_LOCAL | \
|
||||||
SCU_CONF_EHS_FAST_LOCAL | \
|
SCU_CONF_EHS_FAST_LOCAL | \
|
||||||
SCU_CONF_EZI_EN_IN_BUFFER_LOCAL | \
|
SCU_CONF_EZI_EN_IN_BUFFER_LOCAL | \
|
||||||
SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL)
|
SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL)
|
||||||
#define SCU_SSP_IO_LOCAL SCU_GPIO_FAST_LOCAL
|
#define SCU_SSP_IO_LOCAL SCU_GPIO_FAST_LOCAL
|
||||||
|
|
||||||
// Function select values
|
// Function select values
|
||||||
#define SCU_CONF_FUNCTION0_LOCAL (0x0)
|
#define SCU_CONF_FUNCTION0_LOCAL (0x0)
|
||||||
#define SCU_CONF_FUNCTION1_LOCAL (0x1)
|
#define SCU_CONF_FUNCTION1_LOCAL (0x1)
|
||||||
#define SCU_CONF_FUNCTION4_LOCAL (0x4)
|
#define SCU_CONF_FUNCTION4_LOCAL (0x4)
|
||||||
#define SCU_CONF_FUNCTION5_LOCAL (0x5)
|
#define SCU_CONF_FUNCTION5_LOCAL (0x5)
|
||||||
#define SCU_GPIO_NOPULL_LOCAL (SCU_CONF_EZI_EN_IN_BUFFER_LOCAL | SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL)
|
#define SCU_GPIO_NOPULL_LOCAL (SCU_CONF_EZI_EN_IN_BUFFER_LOCAL | SCU_CONF_ZIF_DIS_IN_GLITCH_FILT_LOCAL)
|
||||||
#define SCU_GPIO_PUP_LOCAL (SCU_CONF_EZI_EN_IN_BUFFER_LOCAL)
|
#define SCU_GPIO_PUP_LOCAL (SCU_CONF_EZI_EN_IN_BUFFER_LOCAL)
|
||||||
|
|
||||||
// SSP1 pins (for FPGA programming)
|
// SSP1 pins (for FPGA programming)
|
||||||
#define SCU_SSP1_CIPO_LOCAL (PIN_GROUP1_LOCAL + PIN3_LOCAL) // P1_3
|
#define SCU_SSP1_CIPO_LOCAL (PIN_GROUP1_LOCAL + PIN3_LOCAL) // P1_3
|
||||||
#define SCU_SSP1_COPI_LOCAL (PIN_GROUP1_LOCAL + PIN4_LOCAL) // P1_4
|
#define SCU_SSP1_COPI_LOCAL (PIN_GROUP1_LOCAL + PIN4_LOCAL) // P1_4
|
||||||
#define SCU_SSP1_SCK_LOCAL (PIN_GROUP1_LOCAL + PIN19_LOCAL) // P1_19
|
#define SCU_SSP1_SCK_LOCAL (PIN_GROUP1_LOCAL + PIN19_LOCAL) // P1_19
|
||||||
|
|
||||||
// FPGA control pins
|
// FPGA control pins
|
||||||
#define SCU_FPGA_CRESET_LOCAL (PIN_GROUP5_LOCAL + PIN2_LOCAL) // P5_2 GPIO2[11]
|
#define SCU_FPGA_CRESET_LOCAL (PIN_GROUP5_LOCAL + PIN2_LOCAL) // P5_2 GPIO2[11]
|
||||||
#define SCU_FPGA_CDONE_LOCAL (PIN_GROUP4_LOCAL + PIN10_LOCAL) // P4_10 GPIO5[14]
|
#define SCU_FPGA_CDONE_LOCAL (PIN_GROUP4_LOCAL + PIN10_LOCAL) // P4_10 GPIO5[14]
|
||||||
#define SCU_FPGA_SPI_CS_LOCAL (PIN_GROUP5_LOCAL + PIN1_LOCAL) // P5_1 GPIO2[10]
|
#define SCU_FPGA_SPI_CS_LOCAL (PIN_GROUP5_LOCAL + PIN1_LOCAL) // P5_1 GPIO2[10]
|
||||||
|
|
||||||
// GPIO register addresses for direct MMIO access
|
// GPIO register addresses for direct MMIO access
|
||||||
#define GPIO_LPC_BASE_LOCAL 0x400F4000
|
#define GPIO_LPC_BASE_LOCAL 0x400F4000
|
||||||
#define GPIO_DIR_BASE (GPIO_LPC_BASE_LOCAL + 0x2000) // Direction registers
|
#define GPIO_DIR_BASE (GPIO_LPC_BASE_LOCAL + 0x2000) // Direction registers
|
||||||
#define GPIO_SET_BASE (GPIO_LPC_BASE_LOCAL + 0x2200) // Set registers
|
#define GPIO_SET_BASE (GPIO_LPC_BASE_LOCAL + 0x2200) // Set registers
|
||||||
#define GPIO_CLR_BASE (GPIO_LPC_BASE_LOCAL + 0x2280) // Clear registers
|
#define GPIO_CLR_BASE (GPIO_LPC_BASE_LOCAL + 0x2280) // Clear registers
|
||||||
#define GPIO_PIN_BASE (GPIO_LPC_BASE_LOCAL + 0x2100) // Pin read registers
|
#define GPIO_PIN_BASE (GPIO_LPC_BASE_LOCAL + 0x2100) // Pin read registers
|
||||||
|
|
||||||
// GPIO port access macros
|
// GPIO port access macros
|
||||||
#define GPIO_DIR(port) MMIO32_LOCAL(GPIO_DIR_BASE + (port)*4)
|
#define GPIO_DIR(port) MMIO32_LOCAL(GPIO_DIR_BASE + (port) * 4)
|
||||||
#define GPIO_SET(port) MMIO32_LOCAL(GPIO_SET_BASE + (port)*4)
|
#define GPIO_SET(port) MMIO32_LOCAL(GPIO_SET_BASE + (port) * 4)
|
||||||
#define GPIO_CLR(port) MMIO32_LOCAL(GPIO_CLR_BASE + (port)*4)
|
#define GPIO_CLR(port) MMIO32_LOCAL(GPIO_CLR_BASE + (port) * 4)
|
||||||
#define GPIO_PIN(port) MMIO32_LOCAL(GPIO_PIN_BASE + (port)*4)
|
#define GPIO_PIN(port) MMIO32_LOCAL(GPIO_PIN_BASE + (port) * 4)
|
||||||
|
|
||||||
// FPGA control GPIO pins
|
// FPGA control GPIO pins
|
||||||
// GPIO2[11] = CRESET, GPIO5[14] = CDONE, GPIO2[10] = SPI_CS
|
// GPIO2[11] = CRESET, GPIO5[14] = CDONE, GPIO2[10] = SPI_CS
|
||||||
#define FPGA_CRESET_PORT 2
|
#define FPGA_CRESET_PORT 2
|
||||||
#define FPGA_CRESET_PIN 11
|
#define FPGA_CRESET_PIN 11
|
||||||
#define FPGA_CDONE_PORT 5
|
#define FPGA_CDONE_PORT 5
|
||||||
#define FPGA_CDONE_PIN 14
|
#define FPGA_CDONE_PIN 14
|
||||||
#define FPGA_SPI_CS_PORT 2
|
#define FPGA_SPI_CS_PORT 2
|
||||||
#define FPGA_SPI_CS_PIN 10
|
#define FPGA_SPI_CS_PIN 10
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Canonical Default Values - SINGLE SOURCE OF TRUTH
|
// Canonical Default Values - SINGLE SOURCE OF TRUTH
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
/* Define the canonical RX defaults in ONE place */
|
/* Define the canonical RX defaults in ONE place */
|
||||||
#define FPGA_RX_DEFAULT_DC_WIDTH 0x04 /* Typical for 40MHz stability */
|
#define FPGA_RX_DEFAULT_DC_WIDTH 0x04 /* Typical for 40MHz stability */
|
||||||
#define FPGA_RX_DEFAULT_ADAPT_RATE 0x08 /* Typical for 40MHz stability */
|
#define FPGA_RX_DEFAULT_ADAPT_RATE 0x08 /* Typical for 40MHz stability */
|
||||||
#define FPGA_RX_DEFAULT_DIGITAL_GAIN 0x00 /* No shift initially */
|
#define FPGA_RX_DEFAULT_DIGITAL_GAIN 0x00 /* No shift initially */
|
||||||
|
|
||||||
/* Define TX defaults */
|
/* Define TX defaults */
|
||||||
#define FPGA_TX_DEFAULT_NCO_CTRL 0x00 /* NCO disabled */
|
#define FPGA_TX_DEFAULT_NCO_CTRL 0x00 /* NCO disabled */
|
||||||
#define FPGA_TX_DEFAULT_INTERP 0x00 /* No interpolation */
|
#define FPGA_TX_DEFAULT_INTERP 0x00 /* No interpolation */
|
||||||
#define FPGA_TX_DEFAULT_PHASE_STEP 0x00 /* Zero phase step */
|
#define FPGA_TX_DEFAULT_PHASE_STEP 0x00 /* Zero phase step */
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Static Variables - Declare BEFORE use
|
||||||
|
// ============================================================================
|
||||||
|
static fpga_mode_t current_mode = FPGA_MODE_OFF;
|
||||||
|
// Cached register values for debug reads (since reads may require mode switch)
|
||||||
|
static uint8_t fpga_reg_cache[6] = {0, 0x01, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
// ============================================================================
|
// Context structure for SPIFI-based reading
|
||||||
// Static Variables - Declare BEFORE use
|
struct spifi_fpga_read_ctx {
|
||||||
// ============================================================================
|
|
||||||
static fpga_mode_t current_mode = FPGA_MODE_OFF;
|
|
||||||
// Cached register values for debug reads (since reads may require mode switch)
|
|
||||||
static uint8_t fpga_reg_cache[6] = {0, 0x01, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
// Context structure for SPIFI-based reading
|
|
||||||
struct spifi_fpga_read_ctx {
|
|
||||||
const uint8_t* mem_ptr; // Current read position in SPIFI memory
|
const uint8_t* mem_ptr; // Current read position in SPIFI memory
|
||||||
size_t next_block_sz;
|
size_t next_block_sz;
|
||||||
uint8_t init_flag;
|
uint8_t init_flag;
|
||||||
uint8_t buffer[4096 + 2]; // Compressed block + next size
|
uint8_t buffer[4128 + 2]; // Compressed block + next size
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Low-Level Helper Functions
|
// Low-Level Helper Functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Simple delay loop
|
// Simple delay loop
|
||||||
static void delay_cycles(volatile uint32_t count) {
|
static void delay_cycles(volatile uint32_t count) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
__asm__ volatile ("nop");
|
__asm__ volatile("nop");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Microsecond delay (approximate, assuming ~200MHz clock)
|
// Microsecond delay (approximate, assuming ~200MHz clock)
|
||||||
static void delay_us(uint32_t us) {
|
static void delay_us(uint32_t us) {
|
||||||
// ~50 cycles per microsecond at 200MHz
|
// ~50 cycles per microsecond at 200MHz
|
||||||
delay_cycles(us * 50);
|
delay_cycles(us * 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSP1 transfer one byte
|
// SSP1 transfer one byte
|
||||||
static uint8_t ssp1_transfer_byte(uint8_t data) {
|
static uint8_t ssp1_transfer_byte(uint8_t data) {
|
||||||
// Wait for TX FIFO not full
|
// Wait for TX FIFO not full
|
||||||
while ((SSP1_SR_LOCAL & SSP_SR_TNF_LOCAL) == 0) {}
|
while ((SSP1_SR_LOCAL & SSP_SR_TNF_LOCAL) == 0) {
|
||||||
|
}
|
||||||
SSP1_DR_LOCAL = data;
|
SSP1_DR_LOCAL = data;
|
||||||
// Wait for not busy
|
// Wait for not busy
|
||||||
while (SSP1_SR_LOCAL & SSP_SR_BSY_LOCAL) {}
|
while (SSP1_SR_LOCAL & SSP_SR_BSY_LOCAL) {
|
||||||
// Wait for RX FIFO not empty
|
|
||||||
while ((SSP1_SR_LOCAL & SSP_SR_RNE_LOCAL) == 0) {}
|
|
||||||
return SSP1_DR_LOCAL;
|
|
||||||
}
|
}
|
||||||
|
// Wait for RX FIFO not empty
|
||||||
|
while ((SSP1_SR_LOCAL & SSP_SR_RNE_LOCAL) == 0) {
|
||||||
|
}
|
||||||
|
return SSP1_DR_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
// Configure SSP1 for iCE40 programming (SPI mode 3: CPOL=1, CPHA=1)
|
// Configure SSP1 for iCE40 programming (SPI mode 3: CPOL=1, CPHA=1)
|
||||||
static void ssp1_init_ice40(void) {
|
static void ssp1_init_ice40(void) {
|
||||||
// Disable SSP1 first
|
// Disable SSP1 first
|
||||||
SSP1_CR1_LOCAL = 0;
|
SSP1_CR1_LOCAL = 0;
|
||||||
|
|
||||||
@@ -194,20 +196,20 @@
|
|||||||
|
|
||||||
// Enable SSP1
|
// Enable SSP1
|
||||||
SSP1_CR1_LOCAL = SSP_CR1_SSE;
|
SSP1_CR1_LOCAL = SSP_CR1_SSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure SSP1 pins via SCU
|
// Configure SSP1 pins via SCU
|
||||||
static void configure_ssp1_pins(void) {
|
static void configure_ssp1_pins(void) {
|
||||||
// P1_3 = SSP1_MISO (function 5)
|
// P1_3 = SSP1_MISO (function 5)
|
||||||
MMIO32_LOCAL(SCU_SSP1_CIPO_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION5_LOCAL;
|
MMIO32_LOCAL(SCU_SSP1_CIPO_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION5_LOCAL;
|
||||||
// P1_4 = SSP1_MOSI (function 5)
|
// P1_4 = SSP1_MOSI (function 5)
|
||||||
MMIO32_LOCAL(SCU_SSP1_COPI_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION5_LOCAL;
|
MMIO32_LOCAL(SCU_SSP1_COPI_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION5_LOCAL;
|
||||||
// P1_19 = SSP1_SCK (function 1)
|
// P1_19 = SSP1_SCK (function 1)
|
||||||
MMIO32_LOCAL(SCU_SSP1_SCK_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION1_LOCAL;
|
MMIO32_LOCAL(SCU_SSP1_SCK_LOCAL) = SCU_SSP_IO_LOCAL | SCU_CONF_FUNCTION1_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure FPGA control pins via SCU and GPIO
|
// Configure FPGA control pins via SCU and GPIO
|
||||||
static void configure_fpga_control_pins(void) {
|
static void configure_fpga_control_pins(void) {
|
||||||
// P5_2 = GPIO2[11] = CRESET (function 0, output)
|
// P5_2 = GPIO2[11] = CRESET (function 0, output)
|
||||||
MMIO32_LOCAL(SCU_FPGA_CRESET_LOCAL) = SCU_GPIO_NOPULL_LOCAL | SCU_CONF_FUNCTION0_LOCAL;
|
MMIO32_LOCAL(SCU_FPGA_CRESET_LOCAL) = SCU_GPIO_NOPULL_LOCAL | SCU_CONF_FUNCTION0_LOCAL;
|
||||||
// P4_10 = GPIO5[14] = CDONE (function 4, input with pullup)
|
// P4_10 = GPIO5[14] = CDONE (function 4, input with pullup)
|
||||||
@@ -222,57 +224,56 @@
|
|||||||
|
|
||||||
// CDONE is input (GPIO5[14])
|
// CDONE is input (GPIO5[14])
|
||||||
GPIO_DIR(FPGA_CDONE_PORT) &= ~(1 << FPGA_CDONE_PIN);
|
GPIO_DIR(FPGA_CDONE_PORT) &= ~(1 << FPGA_CDONE_PIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GPIO control helpers
|
// GPIO control helpers
|
||||||
static void fpga_creset_low(void) {
|
static void fpga_creset_low(void) {
|
||||||
GPIO_CLR(FPGA_CRESET_PORT) = (1 << FPGA_CRESET_PIN);
|
GPIO_CLR(FPGA_CRESET_PORT) = (1 << FPGA_CRESET_PIN);
|
||||||
}
|
}
|
||||||
static void fpga_creset_high(void) {
|
static void fpga_creset_high(void) {
|
||||||
GPIO_SET(FPGA_CRESET_PORT) = (1 << FPGA_CRESET_PIN);
|
GPIO_SET(FPGA_CRESET_PORT) = (1 << FPGA_CRESET_PIN);
|
||||||
}
|
}
|
||||||
static void fpga_cs_low(void) {
|
static void fpga_cs_low(void) {
|
||||||
GPIO_CLR(FPGA_SPI_CS_PORT) = (1 << FPGA_SPI_CS_PIN);
|
GPIO_CLR(FPGA_SPI_CS_PORT) = (1 << FPGA_SPI_CS_PIN);
|
||||||
}
|
}
|
||||||
static void fpga_cs_high(void) {
|
static void fpga_cs_high(void) {
|
||||||
GPIO_SET(FPGA_SPI_CS_PORT) = (1 << FPGA_SPI_CS_PIN);
|
GPIO_SET(FPGA_SPI_CS_PORT) = (1 << FPGA_SPI_CS_PIN);
|
||||||
}
|
}
|
||||||
static bool fpga_cdone_read(void) {
|
static bool fpga_cdone_read(void) {
|
||||||
return (GPIO_PIN(FPGA_CDONE_PORT) & (1 << FPGA_CDONE_PIN)) != 0;
|
return (GPIO_PIN(FPGA_CDONE_PORT) & (1 << FPGA_CDONE_PIN)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// FPGA Register Access via SPI (iCE40)
|
// FPGA Register Access via SPI (iCE40)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// These functions allow reading/writing FPGA internal registers via SPI.
|
// These functions allow reading/writing FPGA internal registers via SPI.
|
||||||
// The FPGA bitstream implements a simple SPI register interface.
|
// The FPGA bitstream implements a simple SPI register interface.
|
||||||
//
|
//
|
||||||
// FPGA Register Map:
|
// FPGA Register Map:
|
||||||
// Reg 1 (CTRL): DC_BLOCK(b0), QUARTER_SHIFT_EN(b1), QUARTER_SHIFT_UP(b2), PRBS(b6), TRIGGER_EN(b7)
|
// Reg 1 (CTRL): DC_BLOCK(b0), QUARTER_SHIFT_EN(b1), QUARTER_SHIFT_UP(b2), PRBS(b6), TRIGGER_EN(b7)
|
||||||
// Reg 2 (RX_DECIM): Decimation ratio [2:0]
|
// Reg 2 (RX_DECIM): Decimation ratio [2:0]
|
||||||
// Reg 3 (RX/TX): RX Digital Shift OR TX NCO Control
|
// Reg 3 (RX/TX): RX Digital Shift OR TX NCO Control
|
||||||
// Reg 4 (RX_DC_BLOCK_WIDTH/TX_INTERP) [2:0]
|
// Reg 4 (RX_DC_BLOCK_WIDTH/TX_INTERP) [2:0]
|
||||||
// Reg 5 (RX_DC_ADAPT_RATE/TX_PSTEP) [7:0]
|
// Reg 5 (RX_DC_ADAPT_RATE/TX_PSTEP) [7:0]
|
||||||
//
|
//
|
||||||
// SPI Protocol:
|
// SPI Protocol:
|
||||||
// Read: Send [reg & 0x7F, 0x00, 0x00] -> value in byte 3
|
// Read: Send [reg & 0x7F, 0x00, 0x00] -> value in byte 3
|
||||||
// Write: Send [(reg | 0x80), value, 0x00]
|
// Write: Send [(reg | 0x80), value, 0x00]
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// SPI Mode Switching
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
// ============================================================================
|
// Configure SSP1 for iCE40 FPGA register access (Mode 3, 8-bit)
|
||||||
// SPI Mode Switching
|
static void ssp1_set_mode_ice40(void) {
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Configure SSP1 for iCE40 FPGA register access (Mode 3, 8-bit)
|
|
||||||
static void ssp1_set_mode_ice40(void) {
|
|
||||||
SSP1_CR1_LOCAL = 0; // Disable SSP1
|
SSP1_CR1_LOCAL = 0; // Disable SSP1
|
||||||
SSP1_CR0_LOCAL = SSP_CR0_DSS_8BIT | SSP_CR0_FRF_SPI | SSP_CR0_CPOL | SSP_CR0_CPHA | (21 << 8);
|
SSP1_CR0_LOCAL = SSP_CR0_DSS_8BIT | SSP_CR0_FRF_SPI | SSP_CR0_CPOL | SSP_CR0_CPHA | (21 << 8);
|
||||||
SSP1_CPSR_LOCAL = 2;
|
SSP1_CPSR_LOCAL = 2;
|
||||||
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Enable SSP1
|
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Enable SSP1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure SSP1 back to MAX2831 mode (Mode 0, 9-bit)
|
// Configure SSP1 back to MAX2831 mode (Mode 0, 9-bit)
|
||||||
static void ssp1_set_mode_max2831(void) {
|
static void ssp1_set_mode_max2831(void) {
|
||||||
SSP1_CR1_LOCAL = 0; // Disable SSP1
|
SSP1_CR1_LOCAL = 0; // Disable SSP1
|
||||||
SSP1_CR0_LOCAL = (0x08) | // 9-bit data (DSS = 0x08)
|
SSP1_CR0_LOCAL = (0x08) | // 9-bit data (DSS = 0x08)
|
||||||
(0x00) | // SPI frame format
|
(0x00) | // SPI frame format
|
||||||
@@ -281,15 +282,14 @@
|
|||||||
(21 << 8); // SCR = 21
|
(21 << 8); // SCR = 21
|
||||||
SSP1_CPSR_LOCAL = 2;
|
SSP1_CPSR_LOCAL = 2;
|
||||||
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Enable SSP1
|
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Enable SSP1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Low-Level SPI Register Access (internal, no mode switch)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
// ============================================================================
|
// Read an FPGA register via SPI
|
||||||
// Low-Level SPI Register Access (internal, no mode switch)
|
static uint8_t fpga_spi_read(uint8_t reg) {
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Read an FPGA register via SPI
|
|
||||||
static uint8_t fpga_spi_read(uint8_t reg) {
|
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
fpga_cs_low();
|
fpga_cs_low();
|
||||||
ssp1_transfer_byte(reg & 0x7F); // Clear MSB for read
|
ssp1_transfer_byte(reg & 0x7F); // Clear MSB for read
|
||||||
@@ -297,24 +297,24 @@
|
|||||||
value = ssp1_transfer_byte(0x00); // Read value
|
value = ssp1_transfer_byte(0x00); // Read value
|
||||||
fpga_cs_high();
|
fpga_cs_high();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write an FPGA register via SPI
|
// Write an FPGA register via SPI
|
||||||
static void fpga_spi_write(uint8_t reg, uint8_t value) {
|
static void fpga_spi_write(uint8_t reg, uint8_t value) {
|
||||||
fpga_cs_low();
|
fpga_cs_low();
|
||||||
ssp1_transfer_byte((reg & 0x7F) | 0x80); // Set MSB for write
|
ssp1_transfer_byte((reg & 0x7F) | 0x80); // Set MSB for write
|
||||||
ssp1_transfer_byte(value);
|
ssp1_transfer_byte(value);
|
||||||
ssp1_transfer_byte(0x00); // Dummy byte
|
ssp1_transfer_byte(0x00); // Dummy byte
|
||||||
fpga_cs_high();
|
fpga_cs_high();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Public Debug Functions (switch SPI mode, access register, switch back)
|
// Public Debug Functions (switch SPI mode, access register, switch back)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Public function to read FPGA register (callable from C++ application code)
|
// Public function to read FPGA register (callable from C++ application code)
|
||||||
// Switches SPI mode, reads register, switches back
|
// Switches SPI mode, reads register, switches back
|
||||||
uint8_t fpga_debug_register_read(uint8_t reg) {
|
uint8_t fpga_debug_register_read(uint8_t reg) {
|
||||||
if (reg == 0 || reg > 5) return 0xFF;
|
if (reg == 0 || reg > 5) return 0xFF;
|
||||||
|
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
@@ -324,10 +324,10 @@
|
|||||||
|
|
||||||
fpga_reg_cache[reg] = value;
|
fpga_reg_cache[reg] = value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public function to write FPGA register (callable from C++ application code)
|
// Public function to write FPGA register (callable from C++ application code)
|
||||||
void fpga_debug_register_write(uint8_t reg, uint8_t value) {
|
void fpga_debug_register_write(uint8_t reg, uint8_t value) {
|
||||||
if (reg == 0 || reg > 5) return;
|
if (reg == 0 || reg > 5) return;
|
||||||
|
|
||||||
ssp1_set_mode_ice40();
|
ssp1_set_mode_ice40();
|
||||||
@@ -335,13 +335,13 @@
|
|||||||
ssp1_set_mode_max2831();
|
ssp1_set_mode_max2831();
|
||||||
|
|
||||||
fpga_reg_cache[reg] = value;
|
fpga_reg_cache[reg] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Public Register Access (wraps debug functions)
|
// Public Register Access (wraps debug functions)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
uint8_t fpga_register_read(uint8_t reg) {
|
uint8_t fpga_register_read(uint8_t reg) {
|
||||||
if (reg == 0 || reg > 5) return 0xFF;
|
if (reg == 0 || reg > 5) return 0xFF;
|
||||||
|
|
||||||
ssp1_set_mode_ice40();
|
ssp1_set_mode_ice40();
|
||||||
@@ -350,9 +350,9 @@
|
|||||||
|
|
||||||
fpga_reg_cache[reg] = val;
|
fpga_reg_cache[reg] = val;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_register_write(uint8_t reg, uint8_t value) {
|
void fpga_register_write(uint8_t reg, uint8_t value) {
|
||||||
if (reg == 0 || reg > 5) return;
|
if (reg == 0 || reg > 5) return;
|
||||||
|
|
||||||
ssp1_set_mode_ice40();
|
ssp1_set_mode_ice40();
|
||||||
@@ -360,33 +360,33 @@
|
|||||||
ssp1_set_mode_max2831();
|
ssp1_set_mode_max2831();
|
||||||
|
|
||||||
fpga_reg_cache[reg] = value;
|
fpga_reg_cache[reg] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Mode Management
|
// Mode Management
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
fpga_mode_t fpga_get_mode(void) {
|
fpga_mode_t fpga_get_mode(void) {
|
||||||
return current_mode;
|
return current_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fpga_set_mode with consistent values */
|
/* fpga_set_mode with consistent values */
|
||||||
void fpga_set_mode(fpga_mode_t mode) {
|
void fpga_set_mode(fpga_mode_t mode) {
|
||||||
current_mode = mode;
|
current_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// RX Mode Functions (with mode assertion)
|
// RX Mode Functions (with mode assertion)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/* RX decimation */
|
/* RX decimation */
|
||||||
void fpga_rx_set_decimation(uint8_t ratio) {
|
void fpga_rx_set_decimation(uint8_t ratio) {
|
||||||
if (current_mode != FPGA_MODE_RX) return;
|
if (current_mode != FPGA_MODE_RX) return;
|
||||||
fpga_register_write(FPGA_REG_DECIM, ratio & 0x07);
|
fpga_register_write(FPGA_REG_DECIM, ratio & 0x07);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX DC block enable (bit 0 of register 1) */
|
/* RX DC block enable (bit 0 of register 1) */
|
||||||
void fpga_rx_enable_dc_block(bool enable) {
|
void fpga_rx_enable_dc_block(bool enable) {
|
||||||
if (current_mode != FPGA_MODE_RX) return;
|
if (current_mode != FPGA_MODE_RX) return;
|
||||||
uint8_t ctrl = fpga_register_read(FPGA_REG_CTRL);
|
uint8_t ctrl = fpga_register_read(FPGA_REG_CTRL);
|
||||||
if (enable)
|
if (enable)
|
||||||
@@ -394,33 +394,33 @@
|
|||||||
else
|
else
|
||||||
ctrl &= ~FPGA_CTRL_DC_BLOCK_EN;
|
ctrl &= ~FPGA_CTRL_DC_BLOCK_EN;
|
||||||
fpga_register_write(FPGA_REG_CTRL, ctrl);
|
fpga_register_write(FPGA_REG_CTRL, ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX Functions with mode assertion */
|
/* RX Functions with mode assertion */
|
||||||
void fpga_rx_set_digital_gain(uint8_t shift) {
|
void fpga_rx_set_digital_gain(uint8_t shift) {
|
||||||
if (current_mode != FPGA_MODE_RX) {
|
if (current_mode != FPGA_MODE_RX) {
|
||||||
/* Log error or assert - wrong mode! */
|
/* Log error or assert - wrong mode! */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fpga_register_write(FPGA_REG_SHARED_3, shift & FPGA_RX_GAIN_SHIFT_MASK);
|
fpga_register_write(FPGA_REG_SHARED_3, shift & FPGA_RX_GAIN_SHIFT_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_rx_set_dc_block_width(uint8_t width) {
|
void fpga_rx_set_dc_block_width(uint8_t width) {
|
||||||
if (current_mode != FPGA_MODE_RX) return;
|
if (current_mode != FPGA_MODE_RX) return;
|
||||||
fpga_register_write(FPGA_REG_SHARED_4, width & FPGA_RX_DC_WIDTH_MASK);
|
fpga_register_write(FPGA_REG_SHARED_4, width & FPGA_RX_DC_WIDTH_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_rx_set_dc_adapt_rate(uint8_t rate) {
|
void fpga_rx_set_dc_adapt_rate(uint8_t rate) {
|
||||||
if (current_mode != FPGA_MODE_RX) return;
|
if (current_mode != FPGA_MODE_RX) return;
|
||||||
fpga_register_write(FPGA_REG_SHARED_5, rate);
|
fpga_register_write(FPGA_REG_SHARED_5, rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// TX Mode Functions (with mode assertion)
|
// TX Mode Functions (with mode assertion)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/* TX Functions with mode assertion */
|
/* TX Functions with mode assertion */
|
||||||
void fpga_tx_set_nco_enable(bool enable) {
|
void fpga_tx_set_nco_enable(bool enable) {
|
||||||
if (current_mode != FPGA_MODE_TX) return;
|
if (current_mode != FPGA_MODE_TX) return;
|
||||||
uint8_t val = fpga_register_read(FPGA_REG_SHARED_3);
|
uint8_t val = fpga_register_read(FPGA_REG_SHARED_3);
|
||||||
if (enable)
|
if (enable)
|
||||||
@@ -428,27 +428,26 @@
|
|||||||
else
|
else
|
||||||
val &= ~FPGA_TX_NCO_EN;
|
val &= ~FPGA_TX_NCO_EN;
|
||||||
fpga_register_write(FPGA_REG_SHARED_3, val);
|
fpga_register_write(FPGA_REG_SHARED_3, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_tx_set_interpolation(uint8_t ratio) {
|
void fpga_tx_set_interpolation(uint8_t ratio) {
|
||||||
if (current_mode != FPGA_MODE_TX) return;
|
if (current_mode != FPGA_MODE_TX) return;
|
||||||
fpga_register_write(FPGA_REG_SHARED_4, ratio & FPGA_TX_INTERP_MASK);
|
fpga_register_write(FPGA_REG_SHARED_4, ratio & FPGA_TX_INTERP_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpga_tx_set_phase_step(uint8_t step) {
|
void fpga_tx_set_phase_step(uint8_t step) {
|
||||||
if (current_mode != FPGA_MODE_TX) return;
|
if (current_mode != FPGA_MODE_TX) return;
|
||||||
fpga_register_write(FPGA_REG_SHARED_5, step);
|
fpga_register_write(FPGA_REG_SHARED_5, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// FPGA Register Initialization (called after bitstream load)
|
// FPGA Register Initialization (called after bitstream load)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// Initialize FPGA registers after bitstream load
|
|
||||||
// This is equivalent to fpga_init() in the reference HackRF firmware
|
|
||||||
/* fpga_register_init with consistent values */
|
|
||||||
static void fpga_register_init(void) {
|
|
||||||
|
|
||||||
|
// Initialize FPGA registers after bitstream load
|
||||||
|
// This is equivalent to fpga_init() in the reference HackRF firmware
|
||||||
|
/* fpga_register_init with consistent values */
|
||||||
|
static void fpga_register_init(void) {
|
||||||
/* Boot into RX mode */
|
/* Boot into RX mode */
|
||||||
current_mode = FPGA_MODE_RX;
|
current_mode = FPGA_MODE_RX;
|
||||||
|
|
||||||
@@ -464,15 +463,15 @@
|
|||||||
fpga_reg_cache[3] = FPGA_RX_DEFAULT_DIGITAL_GAIN;
|
fpga_reg_cache[3] = FPGA_RX_DEFAULT_DIGITAL_GAIN;
|
||||||
fpga_reg_cache[4] = FPGA_RX_DEFAULT_DC_WIDTH;
|
fpga_reg_cache[4] = FPGA_RX_DEFAULT_DC_WIDTH;
|
||||||
fpga_reg_cache[5] = FPGA_RX_DEFAULT_ADAPT_RATE;
|
fpga_reg_cache[5] = FPGA_RX_DEFAULT_ADAPT_RATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// LZ4 Decompression for FPGA Bitstream
|
// LZ4 Decompression for FPGA Bitstream
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// SPIFI-based read callback for LZ4 decompression
|
// SPIFI-based read callback for LZ4 decompression
|
||||||
// Reads from SPIFI memory-mapped address instead of using SPI flash driver
|
// Reads from SPIFI memory-mapped address instead of using SPI flash driver
|
||||||
static size_t spifi_fpga_read_block_cb(void* _ctx, uint8_t* out_buffer) {
|
static size_t spifi_fpga_read_block_cb(void* _ctx, uint8_t* out_buffer) {
|
||||||
struct spifi_fpga_read_ctx* ctx = (struct spifi_fpga_read_ctx*)_ctx;
|
struct spifi_fpga_read_ctx* ctx = (struct spifi_fpga_read_ctx*)_ctx;
|
||||||
size_t block_sz = ctx->next_block_sz;
|
size_t block_sz = ctx->next_block_sz;
|
||||||
|
|
||||||
@@ -485,6 +484,10 @@
|
|||||||
|
|
||||||
// Finish at end marker (block_sz == 0)
|
// Finish at end marker (block_sz == 0)
|
||||||
if (block_sz == 0) return 0;
|
if (block_sz == 0) return 0;
|
||||||
|
if (block_sz > 4128) {
|
||||||
|
// Flash corruption detected! Return 0 to abort programming safely.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Read compressed block from SPIFI memory
|
// Read compressed block from SPIFI memory
|
||||||
memcpy(ctx->buffer, ctx->mem_ptr, block_sz + 2);
|
memcpy(ctx->buffer, ctx->mem_ptr, block_sz + 2);
|
||||||
@@ -495,11 +498,11 @@
|
|||||||
|
|
||||||
// Decompress block using LZ4
|
// Decompress block using LZ4
|
||||||
return lz4_blk_decompress(ctx->buffer, out_buffer, block_sz);
|
return lz4_blk_decompress(ctx->buffer, out_buffer, block_sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Program iCE40 FPGA using SPIFI memory-mapped data
|
// Program iCE40 FPGA using SPIFI memory-mapped data
|
||||||
// Based on ice40_spi_syscfg_program() from ice40_spi.c
|
// Based on ice40_spi_syscfg_program() from ice40_spi.c
|
||||||
static bool program_fpga_from_spifi(const uint8_t* bitstream_start) {
|
static bool program_fpga_from_spifi(const uint8_t* bitstream_start, uint8_t* mem_base) {
|
||||||
// Drive CRESET_B = 0, SPI_SS = 0
|
// Drive CRESET_B = 0, SPI_SS = 0
|
||||||
fpga_creset_low();
|
fpga_creset_low();
|
||||||
fpga_cs_low();
|
fpga_cs_low();
|
||||||
@@ -518,17 +521,19 @@
|
|||||||
ssp1_transfer_byte(0);
|
ssp1_transfer_byte(0);
|
||||||
|
|
||||||
// Send configuration image
|
// Send configuration image
|
||||||
// Use static buffers to avoid stack overflow (~8KB would be needed)
|
// Use buffers to avoid stack overflow (~8KB would be needed)
|
||||||
static uint8_t out_buffer[4096];
|
uint8_t* out_buffer = mem_base;
|
||||||
static struct spifi_fpga_read_ctx ctx;
|
struct spifi_fpga_read_ctx* ctx = (struct spifi_fpga_read_ctx*)(out_buffer + 4096);
|
||||||
ctx.mem_ptr = bitstream_start;
|
memset(ctx, 0, sizeof(struct spifi_fpga_read_ctx));
|
||||||
ctx.next_block_sz = 0;
|
memset(out_buffer, 0, 4096);
|
||||||
ctx.init_flag = 0;
|
ctx->mem_ptr = bitstream_start;
|
||||||
|
ctx->next_block_sz = 0;
|
||||||
|
ctx->init_flag = 0;
|
||||||
|
|
||||||
fpga_cs_low();
|
fpga_cs_low();
|
||||||
// Full LZ4 decompress and send all bytes
|
// Full LZ4 decompress and send all bytes
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t read_sz = spifi_fpga_read_block_cb(&ctx, out_buffer);
|
size_t read_sz = spifi_fpga_read_block_cb(ctx, out_buffer);
|
||||||
if (read_sz == 0) break;
|
if (read_sz == 0) break;
|
||||||
for (size_t j = 0; j < read_sz; j++) {
|
for (size_t j = 0; j < read_sz; j++) {
|
||||||
ssp1_transfer_byte(out_buffer[j]);
|
ssp1_transfer_byte(out_buffer[j]);
|
||||||
@@ -561,13 +566,13 @@
|
|||||||
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Re-enable SSP1*/
|
SSP1_CR1_LOCAL = SSP_CR1_SSE; // Re-enable SSP1*/
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Main Initialization Entry Point
|
// Main Initialization Entry Point
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
int fpga_bridge_init(void) {
|
int fpga_bridge_init(uint8_t* mem_base) {
|
||||||
// Enable SSP1 clock for FPGA programming
|
// Enable SSP1 clock for FPGA programming
|
||||||
// Use PLL1 (204MHz) to match original HackRF - IRC (12MHz) is 17x too slow
|
// Use PLL1 (204MHz) to match original HackRF - IRC (12MHz) is 17x too slow
|
||||||
CGU_BASE_SSP1_CLK = CGU_BASE_SSP1_CLK_AUTOBLOCK(1) |
|
CGU_BASE_SSP1_CLK = CGU_BASE_SSP1_CLK_AUTOBLOCK(1) |
|
||||||
@@ -601,7 +606,7 @@
|
|||||||
const uint8_t* bitstream_start = (const uint8_t*)(FPGA_BITSTREAM_MEM_ADDR + bitstream_offset);
|
const uint8_t* bitstream_start = (const uint8_t*)(FPGA_BITSTREAM_MEM_ADDR + bitstream_offset);
|
||||||
|
|
||||||
// Full FPGA programming
|
// Full FPGA programming
|
||||||
bool success = program_fpga_from_spifi(bitstream_start);
|
bool success = program_fpga_from_spifi(bitstream_start, mem_base);
|
||||||
|
|
||||||
// Initialize FPGA registers immediately after programming
|
// Initialize FPGA registers immediately after programming
|
||||||
if (success) {
|
if (success) {
|
||||||
@@ -614,9 +619,8 @@
|
|||||||
// Now switch to MAX2831 mode
|
// Now switch to MAX2831 mode
|
||||||
ssp1_set_mode_max2831();
|
ssp1_set_mode_max2831();
|
||||||
}
|
}
|
||||||
|
|
||||||
return success ? 0 : 2;
|
return success ? 0 : 2;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#warning "Building for HackRF_One with CPLD."
|
#warning "Building for HackRF_One with CPLD."
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ typedef enum {
|
|||||||
|
|
||||||
/* Initialize the FPGA - loads bitstream from SPIFI flash
|
/* Initialize the FPGA - loads bitstream from SPIFI flash
|
||||||
* Returns: 0 on success, non-zero on failure */
|
* Returns: 0 on success, non-zero on failure */
|
||||||
int fpga_bridge_init(void);
|
int fpga_bridge_init(uint8_t* mem_base);
|
||||||
|
|
||||||
/* Set operating mode - MUST be called before using mode-specific functions
|
/* Set operating mode - MUST be called before using mode-specific functions
|
||||||
* This ensures registers 3-5 are interpreted correctly */
|
* This ensures registers 3-5 are interpreted correctly */
|
||||||
|
|||||||
Reference in New Issue
Block a user