[SC64][SW] Made I2C in primer stable

This commit is contained in:
Mateusz Faderewski 2023-01-19 17:15:09 +01:00
parent bc921d762d
commit 6081391bca
8 changed files with 197 additions and 139 deletions

View File

@ -70,7 +70,7 @@ $(BUILD_DIR)/bootloader.elf: $(OBJS) N64.ld
$(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf $(BUILD_DIR)/bootloader.bin: $(BUILD_DIR)/bootloader.elf
@$(OBJCOPY) -O binary $< $@ @$(OBJCOPY) -O binary $< $@
@chksum64 $@ > /dev/null @chksum64 $@ > /dev/null
@truncate --size=1028k $@ @$(PYTHON) tools/strip.py $@
$(BUILD_DIR)/bootloader.hex: $(BUILD_DIR)/bootloader.bin $(BUILD_DIR)/bootloader.hex: $(BUILD_DIR)/bootloader.bin
@$(OBJCOPY) -I binary -O ihex $< $@ @$(OBJCOPY) -I binary -O ihex $< $@

View File

@ -55,6 +55,13 @@ SECTIONS {
. += __stack_size; . += __stack_size;
_sp = .; _sp = .;
.fill : {
. = ALIGN(1024);
FILL(0xFFFFFFFF);
BYTE(0xFFFFFFFF);
. = ORIGIN(rom) + LENGTH(rom);
} > rom
/DISCARD/ : { /DISCARD/ : {
*(.MIPS.*) *(.MIPS.*)
} }

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
import sys
if __name__ == "__main__":
if (len(sys.argv) != 2):
print(f"Usage: python {sys.argv[0]} file_path")
sys.exit(1)
file = sys.argv[1]
try:
data = b''
with open(file, 'rb') as f:
data = f.read()
with open(file, 'wb') as f:
f.write(data.strip(b'\xFF'))
except FileNotFoundError:
print(f"Couldn't open file \"{file}\"")
sys.exit(2)
except Exception as e:
print(e)
sys.exit(3)

View File

@ -126,6 +126,10 @@ void hw_uart_write (uint8_t *data, int length) {
} }
} }
void hw_uart_wait_busy (void) {
while (!(USART1->ISR & USART_ISR_TC));
}
void hw_spi_start (void) { void hw_spi_start (void) {
hw_gpio_reset(GPIO_ID_SPI_CS); hw_gpio_reset(GPIO_ID_SPI_CS);
} }
@ -195,26 +199,42 @@ uint32_t hw_i2c_get_error (void) {
return (I2C1->ISR & I2C_ISR_NACKF); return (I2C1->ISR & I2C_ISR_NACKF);
} }
void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type) { void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
if (type & I2C_START) { while (I2C1->ISR & I2C_ISR_BUSY);
if (tx_length > 0) {
I2C1->ICR = I2C_ICR_NACKCF; I2C1->ICR = I2C_ICR_NACKCF;
} I2C1->CR2 = (
I2C1->CR2 = ( ((rx_length == 0) ? I2C_CR2_AUTOEND : 0) |
((type & I2C_AUTOEND) ? I2C_CR2_AUTOEND : 0) | (tx_length << I2C_CR2_NBYTES_Pos) |
(length << I2C_CR2_NBYTES_Pos) | I2C_CR2_START |
((type & I2C_STOP) ? I2C_CR2_STOP : 0) | (i2c_address << I2C_CR2_SADD_Pos)
((type & I2C_START) ? I2C_CR2_START : 0) | );
((type & I2C_READ) ? I2C_CR2_RD_WRN : 0) | for (int i = 0; i < tx_length; i++) {
(i2c_address << I2C_CR2_SADD_Pos) while (!(I2C1->ISR & I2C_ISR_TXIS));
); I2C1->TXDR = *tx_data++;
for (int i = 0; i < length; i++) {
if (type & I2C_READ) {
while (!(I2C1->ISR & I2C_ISR_RXNE));
*data++ = I2C1->RXDR;
} else if (type & I2C_WRITE) {
while (!(I2C1->ISR & I2C_ISR_TXE));
I2C1->TXDR = *data++;
} }
if (!(I2C1->CR2 & I2C_CR2_AUTOEND)) {
while (!(I2C1->ISR & (I2C_ISR_NACKF | I2C_ISR_TC)));
}
}
if (rx_length > 0) {
I2C1->CR2 = (
I2C_CR2_AUTOEND |
(rx_length << I2C_CR2_NBYTES_Pos) |
I2C_CR2_START |
I2C_CR2_RD_WRN |
(i2c_address << I2C_CR2_SADD_Pos)
);
for (int i = 0; i < rx_length; i++) {
while (!(I2C1->ISR & I2C_ISR_RXNE));
*rx_data++ = I2C1->RXDR;
}
}
if ((tx_length > 0) || (rx_length > 0)) {
while (!(I2C1->ISR & I2C_ISR_STOPF));
} }
} }
@ -438,7 +458,7 @@ static void hw_init_spi (void) {
static void hw_init_i2c (void) { static void hw_init_i2c (void) {
RCC->APBENR1 |= RCC_APBENR1_I2C1EN; RCC->APBENR1 |= RCC_APBENR1_I2C1EN;
I2C1->TIMINGR = 0x10B17DB5UL; I2C1->TIMINGR = 0x00C12166UL;
I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE); I2C1->CR1 |= (I2C_CR1_TCIE | I2C_CR1_STOPIE | I2C_CR1_RXIE | I2C_CR1_TXIE | I2C_CR1_PE);
hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0); hw_gpio_init(GPIO_ID_I2C_SCL, GPIO_ALT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_NONE, GPIO_AF_6, 0);
@ -450,12 +470,12 @@ static void hw_init_uart (void) {
SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP); SYSCFG->CFGR1 |= (SYSCFG_CFGR1_PA12_RMP | SYSCFG_CFGR1_PA11_RMP);
hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_NONE, GPIO_AF_1, 0); hw_gpio_init(GPIO_ID_UART_TX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0); hw_gpio_init(GPIO_ID_UART_RX, GPIO_ALT, GPIO_PP, GPIO_SPEED_LOW, GPIO_PULL_UP, GPIO_AF_1, 0);
USART1->BRR = (64000000UL) / UART_BAUD; USART1->BRR = (64000000UL) / UART_BAUD;
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ; USART1->RQR = USART_RQR_TXFRQ | USART_RQR_RXFRQ;
USART1->CR1 = USART_CR1_FIFOEN | USART_CR1_M0 | USART_CR1_PCE | USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
} }
static void hw_init_tim (void) { static void hw_init_tim (void) {

View File

@ -73,13 +73,14 @@ void hw_gpio_set (gpio_id_t id);
void hw_gpio_reset (gpio_id_t id); void hw_gpio_reset (gpio_id_t id);
void hw_uart_read (uint8_t *data, int length); void hw_uart_read (uint8_t *data, int length);
void hw_uart_write (uint8_t *data, int length); void hw_uart_write (uint8_t *data, int length);
void hw_uart_wait_busy (void);
void hw_spi_start (void); void hw_spi_start (void);
void hw_spi_stop (void); void hw_spi_stop (void);
void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction); void hw_spi_trx (uint8_t *data, int length, spi_direction_t direction);
void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)); void hw_i2c_read (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void)); void hw_i2c_write (uint8_t i2c_address, uint8_t address, uint8_t *data, uint8_t length, void (*callback)(void));
uint32_t hw_i2c_get_error (void); uint32_t hw_i2c_get_error (void);
void hw_i2c_raw (uint8_t i2c_address, uint8_t *data, int length, i2c_type_t type); void hw_i2c_raw (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
void hw_i2c_disable_irq (void); void hw_i2c_disable_irq (void);
void hw_i2c_enable_irq (void); void hw_i2c_enable_irq (void);
void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void)); void hw_tim_setup (tim_id_t id, uint16_t delay, void (*callback)(void));

View File

@ -36,12 +36,14 @@
#define LSC_READ_FEABITS (0xFB) #define LSC_READ_FEABITS (0xFB)
#define ISC_NOOP (0xFF) #define ISC_NOOP (0xFF)
#define ISC_ERASE_SRAM (1 << 16)
#define ISC_ERASE_FEATURE (1 << 17) #define ISC_ERASE_FEATURE (1 << 17)
#define ISC_ERASE_CFG (1 << 18) #define ISC_ERASE_CFG (1 << 18)
#define ISC_ERASE_UFM (1 << 19) #define ISC_ERASE_UFM (1 << 19)
#define LSC_STATUS_1_BUSY (1 << 4) #define LSC_STATUS_CFG_ENABLE (1 << 9)
#define LSC_STATUS_1_FAIL (1 << 5) #define LSC_STATUS_BUSY (1 << 12)
#define LSC_STATUS_FAIL (1 << 13)
#define DEVICE_ID_SIZE (4) #define DEVICE_ID_SIZE (4)
@ -69,50 +71,8 @@ static void lcmxo2_reg_set (uint8_t reg, uint8_t value) {
); );
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
} }
#endif
static void lcmxo2_reset_bus (void) {
#ifdef LCMXO2_I2C
uint8_t reset_data = 0;
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), I2C_START | I2C_AUTOEND | I2C_WRITE);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#endif
}
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type) {
#ifdef LCMXO2_I2C
uint8_t data[4] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
int length = CMD_TWO_OP ? 3 : 4;
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, data, length, I2C_START | I2C_WRITE);
#else
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
fpga_reg_set(REG_VENDOR_DATA, data);
fpga_reg_set(REG_VENDOR_SCR,
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
(type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) |
((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) |
VENDOR_SCR_WRITE |
VENDOR_SCR_START
);
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
#endif
}
static void lcmxo2_finish_cmd (void) {
#ifdef LCMXO2_I2C
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, NULL, 0, I2C_STOP);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#endif
}
static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) { static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
#ifdef LCMXO2_I2C
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_START | I2C_READ);
#else
while (length > 0) { while (length > 0) {
uint32_t block_size = (length > 4) ? 4 : length; uint32_t block_size = (length > 4) ? 4 : length;
fpga_reg_set(REG_VENDOR_SCR, fpga_reg_set(REG_VENDOR_SCR,
@ -129,13 +89,9 @@ static void lcmxo2_read_data (uint8_t *buffer, uint32_t length) {
length -= 1; length -= 1;
} }
} }
#endif
} }
static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) { static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
#ifdef LCMXO2_I2C
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, buffer, length, I2C_WRITE);
#else
while (length > 0) { while (length > 0) {
uint32_t block_size = (length > 4) ? 4 : length; uint32_t block_size = (length > 4) ? 4 : length;
uint32_t data = 0; uint32_t data = 0;
@ -153,94 +109,128 @@ static void lcmxo2_write_data (uint8_t *buffer, uint32_t length) {
); );
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY); while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
} }
}
#endif
static void lcmxo2_reset_bus (void) {
#ifdef LCMXO2_I2C
uint8_t reset_data = 0;
hw_i2c_raw(LCMXO2_I2C_ADDR_RESET, &reset_data, sizeof(reset_data), NULL, 0);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_RSTE);
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#endif
}
static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) {
#ifdef LCMXO2_I2C
uint8_t packet[20] = { cmd, ((arg >> 16) & 0xFF), ((arg >> 8) & 0xFF), (arg & 0xFF) };
int packet_length = ((type == CMD_TWO_OP) ? 3 : 4);
if (write) {
for (int i = 0; i < length; i++) {
packet[packet_length + i] = buffer[i];
}
packet_length += length;
}
hw_i2c_raw(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
#else
uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF);
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);
fpga_reg_set(REG_VENDOR_DATA, data);
fpga_reg_set(REG_VENDOR_SCR,
(LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) |
(type == CMD_DELAYED ? VENDOR_SCR_DELAY : 0) |
((type == CMD_TWO_OP ? 2 : 3) << VENDOR_SCR_LENGTH_BIT) |
VENDOR_SCR_WRITE |
VENDOR_SCR_START
);
while (fpga_reg_get(REG_VENDOR_SCR) & VENDOR_SCR_BUSY);
if (length > 0) {
if (write) {
lcmxo2_write_data(buffer, length);
} else {
lcmxo2_read_data(buffer, length);
}
}
lcmxo2_reg_set(LCMXO2_CFGCR, 0);
#endif #endif
} }
static void lcmxo2_read_device_id (uint8_t *id) { static void lcmxo2_read_device_id (uint8_t *id) {
lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL); lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false);
lcmxo2_read_data(id, DEVICE_ID_SIZE); }
lcmxo2_finish_cmd();
static uint32_t lcmxo2_read_status (void) {
uint32_t status = 0;
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&status), 4, false);
return SWAP32(status);
} }
static bool lcmxo2_wait_busy (void) { static bool lcmxo2_wait_busy (void) {
uint8_t status[4]; uint32_t status;
do { do {
lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL); status = lcmxo2_read_status();
lcmxo2_read_data(status, 4); } while(status & LSC_STATUS_BUSY);
lcmxo2_finish_cmd(); return (status & LSC_STATUS_FAIL);
} while(status[2] & LSC_STATUS_1_BUSY);
return status[2] & LSC_STATUS_1_FAIL;
} }
static bool lcmxo2_enable_flash (void) { static bool lcmxo2_enable_flash (void) {
#ifdef LCMXO2_I2C #ifdef LCMXO2_I2C
lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_NORMAL); lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false);
#else #else
lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL); lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false);
#endif #endif
lcmxo2_finish_cmd();
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_disable_flash (void) { static void lcmxo2_disable_flash (void) {
lcmxo2_wait_busy(); lcmxo2_wait_busy();
lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP); lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false);
lcmxo2_finish_cmd(); lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false);
lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL);
lcmxo2_finish_cmd();
} }
static bool lcmxo2_erase_flash (void) { static bool lcmxo2_erase_sram (void) {
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG, CMD_NORMAL); lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_SRAM, CMD_NORMAL, NULL, 0, false);
lcmxo2_finish_cmd();
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static bool lcmxo2_erase_all (void) { static bool lcmxo2_erase_featbits (void) {
lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_UFM | ISC_ERASE_CFG | ISC_ERASE_FEATURE, CMD_NORMAL); lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false);
lcmxo2_finish_cmd(); return lcmxo2_wait_busy();
}
static bool lcmxo2_erase_flash (void) {
lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false);
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_reset_flash_address (void) { static void lcmxo2_reset_flash_address (void) {
lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL); lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false);
lcmxo2_finish_cmd();
} }
static bool lcmxo2_write_flash_page (uint8_t *buffer) { static bool lcmxo2_write_flash_page (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL); lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true);
lcmxo2_write_data(buffer, FLASH_PAGE_SIZE);
lcmxo2_finish_cmd();
return lcmxo2_wait_busy(); return lcmxo2_wait_busy();
} }
static void lcmxo2_read_flash_page (uint8_t *buffer) { static void lcmxo2_read_flash_page (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED); lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false);
lcmxo2_read_data(buffer, FLASH_PAGE_SIZE);
lcmxo2_finish_cmd();
} }
static void lcmxo2_program_done (void) { static void lcmxo2_program_done (void) {
lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL); lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false);
lcmxo2_finish_cmd();
lcmxo2_wait_busy();
} }
static void lcmxo2_write_featbits (uint8_t *buffer) { static void lcmxo2_write_featbits (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL); lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true);
lcmxo2_write_data(buffer, FEATBITS_SIZE);
lcmxo2_finish_cmd();
} }
static void lcmxo2_read_featbits (uint8_t *buffer) { static void lcmxo2_read_featbits (uint8_t *buffer) {
lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL); lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false);
lcmxo2_read_data(buffer, FEATBITS_SIZE);
lcmxo2_finish_cmd();
} }
static void lcmxo2_refresh (void) { static void lcmxo2_refresh (void) {
lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP); lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false);
lcmxo2_finish_cmd();
} }
static vendor_error_t lcmxo2_fail (vendor_error_t error) { static vendor_error_t lcmxo2_fail (vendor_error_t error) {
@ -248,6 +238,7 @@ static vendor_error_t lcmxo2_fail (vendor_error_t error) {
return error; return error;
} }
uint32_t vendor_flash_size (void) { uint32_t vendor_flash_size (void) {
return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES); return (FLASH_PAGE_SIZE * FLASH_NUM_PAGES);
} }
@ -324,6 +315,10 @@ vendor_error_t vendor_reconfigure (void) {
} }
#define FEATBITS_0_SPI_OFF (1 << 1)
#define FEATBITS_1_PROGRAMN_OFF (1 << 5)
typedef enum { typedef enum {
CMD_GET_PRIMER_ID = '?', CMD_GET_PRIMER_ID = '?',
CMD_PROBE_FPGA = '#', CMD_PROBE_FPGA = '#',
@ -331,13 +326,12 @@ typedef enum {
CMD_GET_DEVICE_ID = 'I', CMD_GET_DEVICE_ID = 'I',
CMD_ENABLE_FLASH = 'E', CMD_ENABLE_FLASH = 'E',
CMD_DISABLE_FLASH = 'D', CMD_DISABLE_FLASH = 'D',
CMD_ERASE_ALL = 'X', CMD_ERASE_FLASH = 'X',
CMD_RESET_ADDRESS = 'A', CMD_RESET_ADDRESS = 'A',
CMD_WRITE_PAGE = 'W', CMD_WRITE_PAGE = 'W',
CMD_READ_PAGE = 'R', CMD_READ_PAGE = 'R',
CMD_PROGRAM_DONE = 'F', CMD_PROGRAM_DONE = 'F',
CMD_WRITE_FEATBITS = 'Q', CMD_INIT_FEATBITS = 'Q',
CMD_READ_FEATBITS = 'Y',
CMD_REFRESH = 'B', CMD_REFRESH = 'B',
} primer_cmd_e; } primer_cmd_e;
@ -346,14 +340,13 @@ static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) {
switch (cmd) { switch (cmd) {
case CMD_WRITE_PAGE: case CMD_WRITE_PAGE:
return (rx_length != FLASH_PAGE_SIZE); return (rx_length != FLASH_PAGE_SIZE);
case CMD_WRITE_FEATBITS:
return (rx_length != FEATBITS_SIZE);
default: default:
return (rx_length != 0); return (rx_length != 0);
} }
return true; return true;
} }
void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) { void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_response_t send_response) {
bool runninng = true; bool runninng = true;
primer_cmd_e cmd; primer_cmd_e cmd;
@ -386,7 +379,6 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
case CMD_PROBE_FPGA: case CMD_PROBE_FPGA:
buffer[0] = fpga_id_get(); buffer[0] = fpga_id_get();
tx_length = 1; tx_length = 1;
error = (buffer[0] != FPGA_ID);
break; break;
case CMD_RESTART: case CMD_RESTART:
@ -403,11 +395,14 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
break; break;
case CMD_DISABLE_FLASH: case CMD_DISABLE_FLASH:
lcmxo2_disable_flash(); if (lcmxo2_read_status() & LSC_STATUS_CFG_ENABLE) {
error = lcmxo2_erase_sram();
lcmxo2_disable_flash();
}
break; break;
case CMD_ERASE_ALL: case CMD_ERASE_FLASH:
error = lcmxo2_erase_all(); error = lcmxo2_erase_flash();
break; break;
case CMD_RESET_ADDRESS: case CMD_RESET_ADDRESS:
@ -427,18 +422,19 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons
lcmxo2_program_done(); lcmxo2_program_done();
break; break;
case CMD_WRITE_FEATBITS: case CMD_INIT_FEATBITS:
lcmxo2_write_featbits(buffer);
break;
case CMD_READ_FEATBITS:
lcmxo2_read_featbits(buffer); lcmxo2_read_featbits(buffer);
tx_length = FEATBITS_SIZE; if ((buffer[0] != FEATBITS_0_SPI_OFF) && (buffer[1] != FEATBITS_1_PROGRAMN_OFF)) {
buffer[0] = FEATBITS_0_SPI_OFF;
buffer[1] = FEATBITS_1_PROGRAMN_OFF;
lcmxo2_erase_featbits();
lcmxo2_write_featbits(buffer);
}
break; break;
case CMD_REFRESH: case CMD_REFRESH:
lcmxo2_refresh(); lcmxo2_refresh();
hw_delay_ms(1000); hw_delay_ms(100);
break; break;
default: default:

View File

@ -4,16 +4,11 @@
#include "vendor.h" #include "vendor.h"
static const uint8_t primer_hello[] = "SC64 Primer\n";
static const uint8_t cmd_token[3] = { 'C', 'M', 'D' }; static const uint8_t cmd_token[3] = { 'C', 'M', 'D' };
static const uint8_t rsp_token[3] = { 'R', 'S', 'P' }; static const uint8_t rsp_token[3] = { 'R', 'S', 'P' };
static const uint8_t err_token[3] = { 'E', 'R', 'R' }; static const uint8_t err_token[3] = { 'E', 'R', 'R' };
static void primer_send_hello (void) {
hw_uart_write((uint8_t *) (primer_hello), sizeof(primer_hello) - 1);
}
static void primer_get_and_calculate_crc32 (uint8_t *buffer, uint8_t rx_length, uint32_t *crc32) { static void primer_get_and_calculate_crc32 (uint8_t *buffer, uint8_t rx_length, uint32_t *crc32) {
hw_uart_read(buffer, rx_length); hw_uart_read(buffer, rx_length);
*crc32 = hw_crc32_calculate(buffer, rx_length); *crc32 = hw_crc32_calculate(buffer, rx_length);
@ -74,10 +69,7 @@ static void primer_send_response (uint8_t cmd, uint8_t *buffer, uint8_t tx_lengt
void primer (void) { void primer (void) {
hw_primer_init(); hw_primer_init();
primer_send_hello();
vendor_initial_configuration(primer_get_command, primer_send_response); vendor_initial_configuration(primer_get_command, primer_send_response);
hw_uart_wait_busy();
hw_reset(NULL); hw_reset(NULL);
} }

View File

@ -19,6 +19,7 @@ class JedecFile:
__fuse_length: int = 0 __fuse_length: int = 0
__fuse_offset: int = 0 __fuse_offset: int = 0
__fuse_data: bytes = b'' __fuse_data: bytes = b''
__fuse_ignore: bool = False
__byte_buffer: int = 0 __byte_buffer: int = 0
def __handle_q_field(self, f: BufferedRandom) -> None: def __handle_q_field(self, f: BufferedRandom) -> None:
@ -77,6 +78,19 @@ class JedecFile:
else: else:
raise JedecError('Unexpected byte inside L field fuse data') raise JedecError('Unexpected byte inside L field fuse data')
def __handle_n_field(self, f: BufferedRandom) -> None:
data = b''
buffer = b''
while (buffer != b'*'):
buffer = f.read(1)
if (buffer == b''):
raise JedecError('Unexpected end of file')
if (buffer != b'*'):
data += buffer
if (data == b'OTE END CONFIG DATA'):
self.__fuse_length = self.__fuse_offset
self.__fuse_ignore = True
def __ignore_field(self, f: BufferedRandom) -> None: def __ignore_field(self, f: BufferedRandom) -> None:
data = None data = None
while (data != b'*'): while (data != b'*'):
@ -88,6 +102,7 @@ class JedecFile:
self.__fuse_length = 0 self.__fuse_length = 0
self.__fuse_offset = 0 self.__fuse_offset = 0
self.__fuse_data = b'' self.__fuse_data = b''
self.__fuse_ignore = False
self.__byte_buffer = 0 self.__byte_buffer = 0
field = None field = None
@ -104,8 +119,10 @@ class JedecFile:
field = f.read(1) field = f.read(1)
if (field == b'Q'): if (field == b'Q'):
self.__handle_q_field(f) self.__handle_q_field(f)
elif (field == b'L'): elif (field == b'L' and not self.__fuse_ignore):
self.__handle_l_field(f) self.__handle_l_field(f)
elif (field == b'N'):
self.__handle_n_field(f)
elif (field == b'\r' or field == b'\n'): elif (field == b'\r' or field == b'\n'):
pass pass
elif (field == b'\x03'): elif (field == b'\x03'):