CPLD: Load bitstream to SRAM at start-up.
This commit is contained in:
@ -25,5 +25,23 @@ set(CMAKE_TOOLCHAIN_FILE toolchain-arm-cortex-m.cmake)
|
|||||||
|
|
||||||
project (hackrf_firmware_all C)
|
project (hackrf_firmware_all C)
|
||||||
|
|
||||||
|
SET(PATH_HACKRF_FIRMWARE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
SET(PATH_HACKRF_CPLD_XSVF ${PATH_HACKRF_FIRMWARE}/cpld/sgpio_if/default.xsvf)
|
||||||
|
SET(PATH_HACKRF ${PATH_HACKRF_FIRMWARE}/..)
|
||||||
|
SET(PATH_HACKRF_FIRMWARE_COMMON ${PATH_HACKRF_FIRMWARE}/common)
|
||||||
|
SET(LIBOPENCM3 ${PATH_HACKRF_FIRMWARE}/libopencm3)
|
||||||
|
SET(PATH_DFU_PY ${PATH_HACKRF_FIRMWARE}/dfu.py)
|
||||||
|
SET(PATH_XSVF_TOOL ${PATH_HACKRF_FIRMWARE}/tools/cpld_crc.py)
|
||||||
|
set(PATH_HACKRF_CPLD_DATA_C ${CMAKE_CURRENT_BINARY_DIR}/hackrf_cpld_data.c)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(libopencm3
|
||||||
|
SOURCE_DIR "${LIBOPENCM3}"
|
||||||
|
BUILD_IN_SOURCE true
|
||||||
|
DOWNLOAD_COMMAND ""
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(blinky)
|
add_subdirectory(blinky)
|
||||||
add_subdirectory(hackrf_usb)
|
add_subdirectory(hackrf_usb)
|
||||||
|
@ -26,10 +26,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define CPLD_XC2C64A_ROWS (98)
|
|
||||||
#define CPLD_XC2C64A_BITS_IN_ROW (274)
|
|
||||||
#define CPLD_XC2C64A_BYTES_IN_ROW ((CPLD_XC2C64A_BITS_IN_ROW + 7) / 8)
|
|
||||||
|
|
||||||
static const uint8_t cpld_xc2c64a_row_address[CPLD_XC2C64A_ROWS] = {
|
static const uint8_t cpld_xc2c64a_row_address[CPLD_XC2C64A_ROWS] = {
|
||||||
0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08,
|
0x00, 0x40, 0x60, 0x20, 0x30, 0x70, 0x50, 0x10, 0x18, 0x58, 0x78, 0x38, 0x28, 0x68, 0x48, 0x08,
|
||||||
0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04,
|
0x0c, 0x4c, 0x6c, 0x2c, 0x3c, 0x7c, 0x5c, 0x1c, 0x14, 0x54, 0x74, 0x34, 0x24, 0x64, 0x44, 0x04,
|
||||||
@ -40,25 +36,6 @@ static const uint8_t cpld_xc2c64a_row_address[CPLD_XC2C64A_ROWS] = {
|
|||||||
0x05, 0x45,
|
0x05, 0x45,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t cpld_xc2c64a_mask[6][CPLD_XC2C64A_BYTES_IN_ROW] = {
|
|
||||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, },
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, },
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0x1f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, },
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x1f, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, },
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0x07, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t cpld_xc2c64a_row_mask_index[CPLD_XC2C64A_ROWS] = {
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 2, 2, 2, 3, 4, 2, 2, 2, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 2, 2, 2, 2, 2, 5, 2, 2, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CPLD_XC2C_IR_INTEST = 0b00000010,
|
CPLD_XC2C_IR_INTEST = 0b00000010,
|
||||||
CPLD_XC2C_IR_BYPASS = 0b11111111,
|
CPLD_XC2C_IR_BYPASS = 0b11111111,
|
||||||
@ -121,12 +98,11 @@ static bool cpld_xc2c_jtag_clock(const jtag_t* const jtag, const uint32_t tms, c
|
|||||||
return gpio_read(jtag->gpio->gpio_tdo);
|
return gpio_read(jtag->gpio->gpio_tdo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpld_xc2c_jtag_shift_ptr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t count) {
|
static void cpld_xc2c_jtag_shift_ptr_tms(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t start, const size_t end, const bool tms) {
|
||||||
for(size_t i=0; i<count; i++) {
|
for(size_t i=start; i<end; i++) {
|
||||||
const size_t byte_n = i >> 3;
|
const size_t byte_n = i >> 3;
|
||||||
const size_t bit_n = i & 7;
|
const size_t bit_n = i & 7;
|
||||||
const uint32_t mask = (1U << bit_n);
|
const uint32_t mask = (1U << bit_n);
|
||||||
const bool tms = (i == (count - 1));
|
|
||||||
|
|
||||||
const uint32_t tdo = cpld_xc2c_jtag_clock(jtag, tms, tdi_tdo[byte_n] & mask) ? 1 : 0;
|
const uint32_t tdo = cpld_xc2c_jtag_clock(jtag, tms, tdi_tdo[byte_n] & mask) ? 1 : 0;
|
||||||
|
|
||||||
@ -135,6 +111,13 @@ static void cpld_xc2c_jtag_shift_ptr(const jtag_t* const jtag, uint8_t* const td
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c_jtag_shift_ptr(const jtag_t* const jtag, uint8_t* const tdi_tdo, const size_t count) {
|
||||||
|
if( count > 0 ) {
|
||||||
|
cpld_xc2c_jtag_shift_ptr_tms(jtag, tdi_tdo, 0, count - 1, false);
|
||||||
|
cpld_xc2c_jtag_shift_ptr_tms(jtag, tdi_tdo, count - 1, count, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t cpld_xc2c_jtag_shift_u32(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi, const size_t count) {
|
static uint32_t cpld_xc2c_jtag_shift_u32(const jtag_t* const jtag, const uint32_t tms, const uint32_t tdi, const size_t count) {
|
||||||
uint32_t tdo = 0;
|
uint32_t tdo = 0;
|
||||||
|
|
||||||
@ -189,11 +172,18 @@ static uint8_t cpld_xc2c_jtag_shift_ir(const jtag_t* const jtag, const cpld_xc2c
|
|||||||
return cpld_xc2c_jtag_shift_ir_pause(jtag, ir, 0);
|
return cpld_xc2c_jtag_shift_ir_pause(jtag, ir, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c_jtag_reset(const jtag_t* const jtag) {
|
||||||
|
/* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram.
|
||||||
|
*/
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b11111, 0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
static void cpld_xc2c_jtag_reset_and_idle(const jtag_t* const jtag) {
|
static void cpld_xc2c_jtag_reset_and_idle(const jtag_t* const jtag) {
|
||||||
/* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram.
|
/* Five TMS=1 to reach Test-Logic-Reset from any point in the TAP state diagram.
|
||||||
* One TMS=0 to move from Test-Logic-Reset to Run-Test-Idle.
|
* One TMS=0 to move from Test-Logic-Reset to Run-Test-Idle.
|
||||||
*/
|
*/
|
||||||
cpld_xc2c_jtag_shift_u32(jtag, 0b011111, 0, 6);
|
cpld_xc2c_jtag_reset(jtag);
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t cpld_xc2c_jtag_idcode(const jtag_t* const jtag) {
|
static uint32_t cpld_xc2c_jtag_idcode(const jtag_t* const jtag) {
|
||||||
@ -215,6 +205,20 @@ static void cpld_xc2c_jtag_conld(const jtag_t* const jtag) {
|
|||||||
|
|
||||||
static void cpld_xc2c_jtag_enable(const jtag_t* const jtag) {
|
static void cpld_xc2c_jtag_enable(const jtag_t* const jtag) {
|
||||||
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_ENABLE);
|
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_ENABLE);
|
||||||
|
cpld_xc2c_jtag_clocks(jtag, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c_jtag_disable(const jtag_t* const jtag) {
|
||||||
|
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_DISABLE);
|
||||||
|
cpld_xc2c_jtag_clocks(jtag, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c_jtag_sram_write(const jtag_t* const jtag) {
|
||||||
|
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c_jtag_sram_read(const jtag_t* const jtag) {
|
||||||
|
cpld_xc2c_jtag_shift_ir(jtag, CPLD_XC2C_IR_ISC_SRAM_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t cpld_xc2c_jtag_bypass(const jtag_t* const jtag, const bool shift_dr) {
|
static uint32_t cpld_xc2c_jtag_bypass(const jtag_t* const jtag, const bool shift_dr) {
|
||||||
@ -265,7 +269,11 @@ static void cpld_xc2c64a_jtag_read_row(const jtag_t* const jtag, uint8_t address
|
|||||||
cpld_xc2c_jtag_clocks(jtag, 100);
|
cpld_xc2c_jtag_clocks(jtag, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_value) {
|
bool cpld_xc2c64a_jtag_checksum(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_verify_t* const verify,
|
||||||
|
uint32_t* const crc_value
|
||||||
|
) {
|
||||||
cpld_xc2c_jtag_reset_and_idle(jtag);
|
cpld_xc2c_jtag_reset_and_idle(jtag);
|
||||||
|
|
||||||
if( cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) &&
|
if( cpld_xc2c64a_jtag_idcode_ok(jtag) && cpld_xc2c_jtag_read_write_protect(jtag) &&
|
||||||
@ -287,9 +295,9 @@ bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_va
|
|||||||
const size_t address = cpld_xc2c64a_row_address[row];
|
const size_t address = cpld_xc2c64a_row_address[row];
|
||||||
cpld_xc2c64a_jtag_read_row(jtag, address, dr);
|
cpld_xc2c64a_jtag_read_row(jtag, address, dr);
|
||||||
|
|
||||||
const size_t mask_index = cpld_xc2c64a_row_mask_index[row];
|
const size_t mask_index = verify->mask_index[row];
|
||||||
for(size_t i=0; i<CPLD_XC2C64A_BYTES_IN_ROW; i++) {
|
for(size_t i=0; i<CPLD_XC2C64A_BYTES_IN_ROW; i++) {
|
||||||
dr[i] &= cpld_xc2c64a_mask[mask_index][i];
|
dr[i] &= verify->mask[mask_index].value[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Important checksum calculation NOTE:
|
/* Important checksum calculation NOTE:
|
||||||
@ -318,3 +326,103 @@ bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_va
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c64a_jtag_sram_write_row(const jtag_t* const jtag, uint8_t address, const uint8_t* const data) {
|
||||||
|
uint8_t write[CPLD_XC2C64A_BYTES_IN_ROW];
|
||||||
|
memcpy(&write[0], data, sizeof(write));
|
||||||
|
|
||||||
|
/* Update-IR or Run-Test/Idle -> Shift-DR */
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3);
|
||||||
|
|
||||||
|
/* Shift-DR -> Shift-DR */
|
||||||
|
cpld_xc2c_jtag_shift_ptr_tms(jtag, &write[0], 0, CPLD_XC2C64A_BITS_IN_ROW, false);
|
||||||
|
|
||||||
|
/* Shift-DR -> Exit1-DR */
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b1000000, address, 7);
|
||||||
|
|
||||||
|
/* Exit1-DR -> Update-DR -> Run-Test/Idle */
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b01, 0b00, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpld_xc2c64a_jtag_sram_read_row(const jtag_t* const jtag, uint8_t* const data, const uint8_t next_address) {
|
||||||
|
/* Run-Test/Idle -> Shift-DR */
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b001, 0b000, 3);
|
||||||
|
|
||||||
|
/* Shift-DR */
|
||||||
|
cpld_xc2c_jtag_shift_ptr_tms(jtag, data, 0, CPLD_XC2C64A_BITS_IN_ROW, false);
|
||||||
|
|
||||||
|
/* Shift-DR -> Exit1-DR */
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b1000000, next_address, 7);
|
||||||
|
|
||||||
|
/* Weird, non-IEEE1532 compliant path through TAP machine, described in Xilinx
|
||||||
|
* Programmer Qualification Specification, applicable only to XC2C64/A.
|
||||||
|
* Exit1-DR -> Pause-DR -> Exit2-DR -> Update-DR -> Run-Test/Idle
|
||||||
|
*/
|
||||||
|
cpld_xc2c_jtag_shift_u32(jtag, 0b0110, 0b0000, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cpld_xc2c64a_jtag_sram_compare_row(const jtag_t* const jtag, const uint8_t* const expected, const uint8_t* const mask, const uint8_t next_address) {
|
||||||
|
/* Run-Test/Idle -> Shift-DR */
|
||||||
|
uint8_t read[CPLD_XC2C64A_BYTES_IN_ROW];
|
||||||
|
memset(read, 0xff, sizeof(read));
|
||||||
|
cpld_xc2c64a_jtag_sram_read_row(jtag, &read[0], next_address);
|
||||||
|
|
||||||
|
bool matched = true;
|
||||||
|
if( (expected != NULL) && (mask != NULL) ) {
|
||||||
|
for(size_t i=0; i<CPLD_XC2C64A_BYTES_IN_ROW; i++) {
|
||||||
|
const uint8_t significant_differences = (read[i] ^ expected[i]) & mask[i];
|
||||||
|
matched &= (significant_differences == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpld_xc2c64a_jtag_sram_write(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_program_t* const program
|
||||||
|
) {
|
||||||
|
cpld_xc2c_jtag_reset_and_idle(jtag);
|
||||||
|
cpld_xc2c_jtag_enable(jtag);
|
||||||
|
|
||||||
|
cpld_xc2c_jtag_sram_write(jtag);
|
||||||
|
|
||||||
|
for(size_t row=0; row<CPLD_XC2C64A_ROWS; row++) {
|
||||||
|
const uint8_t address = cpld_xc2c64a_row_address[row];
|
||||||
|
cpld_xc2c64a_jtag_sram_write_row(jtag, address, &program->row[row].data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpld_xc2c_jtag_disable(jtag);
|
||||||
|
cpld_xc2c_jtag_bypass(jtag, false);
|
||||||
|
cpld_xc2c_jtag_reset(jtag);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cpld_xc2c64a_jtag_sram_verify(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_program_t* const program,
|
||||||
|
const cpld_xc2c64a_verify_t* const verify
|
||||||
|
) {
|
||||||
|
cpld_xc2c_jtag_reset_and_idle(jtag);
|
||||||
|
cpld_xc2c_jtag_enable(jtag);
|
||||||
|
|
||||||
|
cpld_xc2c_jtag_sram_read(jtag);
|
||||||
|
|
||||||
|
/* Tricky loop to read dummy row first, then first address, then loop back to get
|
||||||
|
* the first row's data.
|
||||||
|
*/
|
||||||
|
bool matched = true;
|
||||||
|
for(size_t address_row=0; address_row<=CPLD_XC2C64A_ROWS; address_row++) {
|
||||||
|
const int data_row = (int)address_row - 1;
|
||||||
|
const size_t mask_index = (data_row >= 0) ? verify->mask_index[data_row] : 0;
|
||||||
|
const uint8_t* const expected = (data_row >= 0) ? &program->row[data_row].data[0] : NULL;
|
||||||
|
const uint8_t* const mask = (data_row >= 0) ? &verify->mask[mask_index].value[0] : NULL;
|
||||||
|
const uint8_t next_address = (address_row < CPLD_XC2C64A_ROWS) ? cpld_xc2c64a_row_address[address_row] : 0;
|
||||||
|
matched &= cpld_xc2c64a_jtag_sram_compare_row(jtag, expected, mask, next_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpld_xc2c_jtag_disable(jtag);
|
||||||
|
cpld_xc2c_jtag_bypass(jtag, false);
|
||||||
|
cpld_xc2c_jtag_reset(jtag);
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
@ -27,6 +27,44 @@
|
|||||||
|
|
||||||
#include "cpld_jtag.h"
|
#include "cpld_jtag.h"
|
||||||
|
|
||||||
bool cpld_xc2c64a_jtag_checksum(const jtag_t* const jtag, uint32_t* const crc_value);
|
/* Xilinx CoolRunner II XC2C64A bitstream attributes */
|
||||||
|
#define CPLD_XC2C64A_ROWS (98)
|
||||||
|
#define CPLD_XC2C64A_BITS_IN_ROW (274)
|
||||||
|
#define CPLD_XC2C64A_BYTES_IN_ROW ((CPLD_XC2C64A_BITS_IN_ROW + 7) / 8)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[CPLD_XC2C64A_BYTES_IN_ROW];
|
||||||
|
} cpld_xc2c64a_row_data_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cpld_xc2c64a_row_data_t row[CPLD_XC2C64A_ROWS];
|
||||||
|
} cpld_xc2c64a_program_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t value[CPLD_XC2C64A_BYTES_IN_ROW];
|
||||||
|
} cpld_xc2c64a_row_mask_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cpld_xc2c64a_row_mask_t mask[6];
|
||||||
|
uint8_t mask_index[CPLD_XC2C64A_ROWS];
|
||||||
|
} cpld_xc2c64a_verify_t;
|
||||||
|
|
||||||
|
bool cpld_xc2c64a_jtag_checksum(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_verify_t* const verify,
|
||||||
|
uint32_t* const crc_value
|
||||||
|
);
|
||||||
|
void cpld_xc2c64a_jtag_sram_write(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_program_t* const program
|
||||||
|
);
|
||||||
|
bool cpld_xc2c64a_jtag_sram_verify(
|
||||||
|
const jtag_t* const jtag,
|
||||||
|
const cpld_xc2c64a_program_t* const program,
|
||||||
|
const cpld_xc2c64a_verify_t* const verify
|
||||||
|
);
|
||||||
|
|
||||||
|
extern const cpld_xc2c64a_program_t cpld_hackrf_program_sram;
|
||||||
|
extern const cpld_xc2c64a_verify_t cpld_hackrf_verify;
|
||||||
|
|
||||||
#endif/*__CPLD_XC2C_H__*/
|
#endif/*__CPLD_XC2C_H__*/
|
||||||
|
@ -25,6 +25,12 @@ project(hackrf_usb C)
|
|||||||
|
|
||||||
include(../hackrf-common.cmake)
|
include(../hackrf-common.cmake)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${PATH_HACKRF_CPLD_DATA_C}
|
||||||
|
COMMAND ${PATH_XSVF_TOOL} --code ${PATH_HACKRF_CPLD_XSVF} >${PATH_HACKRF_CPLD_DATA_C}
|
||||||
|
DEPENDS ${PATH_XSVF_TOOL} ${PATH_HACKRF_CPLD_XSVF}
|
||||||
|
)
|
||||||
|
|
||||||
set(SRC_M4
|
set(SRC_M4
|
||||||
hackrf_usb.c
|
hackrf_usb.c
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/tuning.c"
|
||||||
@ -48,6 +54,7 @@ set(SRC_M4
|
|||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/fault_handler.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_jtag.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_xc2c.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/cpld_xc2c.c"
|
||||||
|
"${PATH_HACKRF_CPLD_DATA_C}"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/crc.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/crc.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/lenval.c"
|
||||||
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c"
|
"${PATH_HACKRF_FIRMWARE_COMMON}/xapp058/micro.c"
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "usb_api_sweep.h"
|
#include "usb_api_sweep.h"
|
||||||
#include "usb_api_transceiver.h"
|
#include "usb_api_transceiver.h"
|
||||||
#include "usb_bulk_buffer.h"
|
#include "usb_bulk_buffer.h"
|
||||||
|
#include "cpld_xc2c.h"
|
||||||
|
|
||||||
#include "hackrf-ui.h"
|
#include "hackrf-ui.h"
|
||||||
|
|
||||||
@ -209,6 +210,14 @@ void usb_set_descriptor_by_serial_number(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cpld_jtag_sram_load(jtag_t* const jtag) {
|
||||||
|
cpld_jtag_take(jtag);
|
||||||
|
cpld_xc2c64a_jtag_sram_write(jtag, &cpld_hackrf_program_sram);
|
||||||
|
const bool success = cpld_xc2c64a_jtag_sram_verify(jtag, &cpld_hackrf_program_sram, &cpld_hackrf_verify);
|
||||||
|
cpld_jtag_release(jtag);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
pin_setup();
|
pin_setup();
|
||||||
enable_1v8_power();
|
enable_1v8_power();
|
||||||
@ -220,6 +229,10 @@ int main(void) {
|
|||||||
#endif
|
#endif
|
||||||
cpu_clock_init();
|
cpu_clock_init();
|
||||||
|
|
||||||
|
if( !cpld_jtag_sram_load(&jtag_cpld) ) {
|
||||||
|
// TODO: Fail, do not continue booting.
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef DFU_MODE
|
#ifndef DFU_MODE
|
||||||
usb_set_descriptor_by_serial_number();
|
usb_set_descriptor_by_serial_number();
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,7 +106,7 @@ usb_request_status_t usb_vendor_request_cpld_checksum(
|
|||||||
if (stage == USB_TRANSFER_STAGE_SETUP)
|
if (stage == USB_TRANSFER_STAGE_SETUP)
|
||||||
{
|
{
|
||||||
cpld_jtag_take(&jtag_cpld);
|
cpld_jtag_take(&jtag_cpld);
|
||||||
const bool checksum_success = cpld_xc2c64a_jtag_checksum(&jtag_cpld, &cpld_crc);
|
const bool checksum_success = cpld_xc2c64a_jtag_checksum(&jtag_cpld, &cpld_hackrf_verify, &cpld_crc);
|
||||||
cpld_jtag_release(&jtag_cpld);
|
cpld_jtag_release(&jtag_cpld);
|
||||||
|
|
||||||
if(!checksum_success) {
|
if(!checksum_success) {
|
||||||
|
Reference in New Issue
Block a user