diff --git a/build.sh b/build.sh index fd52d0d..2f81590 100755 --- a/build.sh +++ b/build.sh @@ -83,6 +83,8 @@ build_cic () { build_fpga () { if [ "$BUILT_FPGA" = true ]; then return; fi + build_cic + pushd fw/project/lcmxo2 > /dev/null if [ "$FORCE_CLEAN" = true ]; then rm -rf ./impl1/ diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c index edf2613..aaef8e2 100644 --- a/sw/controller/src/hw.c +++ b/sw/controller/src/hw.c @@ -305,8 +305,8 @@ void hw_spi_tx (uint8_t *data, int length) { } -#define I2C_TIMEOUT_US_BUSY (1000) -#define I2C_TIMEOUT_US_PER_BYTE (100) +#define I2C_TIMEOUT_US_BUSY (10000) +#define I2C_TIMEOUT_US_PER_BYTE (1000) static void hw_i2c_init (void) { RCC->APBENR1 |= RCC_APBENR1_I2C1EN; @@ -331,18 +331,18 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint } } - uint32_t timeout = ((tx_length + rx_length) * I2C_TIMEOUT_US_PER_BYTE); - - hw_timeout_start(); - if (tx_length > 0) { + uint32_t tx_timeout = ((tx_length + 1) * I2C_TIMEOUT_US_PER_BYTE); + + hw_timeout_start(); + I2C1->ICR = I2C_ICR_NACKCF; I2C1->CR2 = ( ((rx_length > 0) ? 0 : I2C_CR2_AUTOEND) | (tx_length << I2C_CR2_NBYTES_Pos) | + I2C_CR2_START | (address << I2C_CR2_SADD_Pos) ); - I2C1->CR2 |= I2C_CR2_START; uint8_t left = tx_length; @@ -358,7 +358,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint return I2C_ERR_NACK; } - if (hw_timeout_occured(timeout)) { + if (hw_timeout_occured(tx_timeout)) { return I2C_ERR_TIMEOUT; } } @@ -368,20 +368,24 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint } while (!(I2C1->ISR & I2C_ISR_TC)) { - if (hw_timeout_occured(timeout)) { + if (hw_timeout_occured(tx_timeout)) { return I2C_ERR_TIMEOUT; } } } if (rx_length > 0) { + uint32_t rx_timeout = ((rx_length + 1) * I2C_TIMEOUT_US_PER_BYTE); + + hw_timeout_start(); + I2C1->CR2 = ( I2C_CR2_AUTOEND | (rx_length << I2C_CR2_NBYTES_Pos) | + I2C_CR2_START | I2C_CR2_RD_WRN | (address << I2C_CR2_SADD_Pos) ); - I2C1->CR2 |= I2C_CR2_START; uint8_t left = rx_length; @@ -393,7 +397,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint left -= 1; } - if (hw_timeout_occured(timeout)) { + if (hw_timeout_occured(rx_timeout)) { return I2C_ERR_TIMEOUT; } } diff --git a/sw/controller/src/lcmxo2.c b/sw/controller/src/lcmxo2.c index 1be5dcd..d7a5a56 100644 --- a/sw/controller/src/lcmxo2.c +++ b/sw/controller/src/lcmxo2.c @@ -121,20 +121,26 @@ static void lcmxo2_reset_bus (void) { #endif } -static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint8_t *buffer, uint8_t length, bool write) { +static bool 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_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length)); + + i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length)); + + return (err != I2C_OK); #else - uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF); lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE); + + uint32_t data = (cmd << 24) | (arg & 0x00FFFFFF); + fpga_reg_set(REG_VENDOR_DATA, data); fpga_reg_set(REG_VENDOR_SCR, (LCMXO2_CFGTXDR << VENDOR_SCR_ADDRESS_BIT) | @@ -143,7 +149,9 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint 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); @@ -151,82 +159,105 @@ static void lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint lcmxo2_read_data(buffer, length); } } + lcmxo2_reg_set(LCMXO2_CFGCR, 0); + + return false; #endif } -static void lcmxo2_read_device_id (uint8_t *id) { - lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false); +static bool lcmxo2_read_device_id (uint8_t *id) { + return lcmxo2_execute_cmd(IDCODE_PUB, 0, CMD_NORMAL, id, DEVICE_ID_SIZE, false); } -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 uint32_t lcmxo2_read_status (uint32_t *status) { + uint32_t tmp = 0; + bool error = lcmxo2_execute_cmd(LSC_READ_STATUS, 0, CMD_NORMAL, (uint8_t *) (&tmp), 4, false); + *status = SWAP32(tmp); + return error; } static bool lcmxo2_wait_busy (void) { + bool error; uint32_t status; do { - status = lcmxo2_read_status(); - } while (status & LSC_STATUS_BUSY); - return (status & LSC_STATUS_FAIL); + error = lcmxo2_read_status(&status); + } while ((!error) && (status & LSC_STATUS_BUSY)); + return (error) || (status & LSC_STATUS_FAIL); } static bool lcmxo2_enable_flash (void) { #ifdef LCMXO2_I2C - lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false); + if (lcmxo2_execute_cmd(ISC_ENABLE, 0x080000, CMD_TWO_OP, NULL, 0, false)) { + return true; + } #else - lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false); + if (lcmxo2_execute_cmd(ISC_ENABLE_X, 0x080000, CMD_NORMAL, NULL, 0, false)) { + return true; + } #endif return lcmxo2_wait_busy(); } -static void lcmxo2_disable_flash (void) { - lcmxo2_wait_busy(); - lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false); - lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false); +static bool lcmxo2_disable_flash (void) { + if (lcmxo2_wait_busy()) { + return true; + } + if (lcmxo2_execute_cmd(ISC_DISABLE, 0, CMD_TWO_OP, NULL, 0, false)) { + return true; + } + return lcmxo2_execute_cmd(ISC_NOOP, 0xFFFFFF, CMD_NORMAL, NULL, 0, false); } static bool lcmxo2_erase_featbits (void) { - lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false); + if (lcmxo2_execute_cmd(ISC_ERASE, ISC_ERASE_FEATURE, CMD_NORMAL, NULL, 0, false)) { + return true; + } 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); + if (lcmxo2_execute_cmd(ISC_ERASE, (ISC_ERASE_UFM | ISC_ERASE_CFG), CMD_NORMAL, NULL, 0, false)) { + return true; + } return lcmxo2_wait_busy(); } -static void lcmxo2_reset_flash_address (void) { - lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false); +static bool lcmxo2_reset_flash_address (void) { + return lcmxo2_execute_cmd(LSC_INIT_ADDRESS, 0, CMD_NORMAL, NULL, 0, false); } static bool lcmxo2_write_flash_page (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true); + if (lcmxo2_execute_cmd(LSC_PROG_INCR_NV, 1, CMD_NORMAL, buffer, FLASH_PAGE_SIZE, true)) { + return true; + } return lcmxo2_wait_busy(); } -static void lcmxo2_read_flash_page (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false); +static bool lcmxo2_read_flash_page (uint8_t *buffer) { + return lcmxo2_execute_cmd(LSC_READ_INCR_NV, 1, CMD_DELAYED, buffer, FLASH_PAGE_SIZE, false); } static bool lcmxo2_program_done (void) { - lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false); + if (lcmxo2_execute_cmd(ISC_PROGRAM_DONE, 0, CMD_NORMAL, NULL, 0, false)) { + return true; + } return lcmxo2_wait_busy(); } static bool lcmxo2_write_featbits (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true); + if (lcmxo2_execute_cmd(LSC_PROG_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, true)) { + return true; + } return lcmxo2_wait_busy(); } -static void lcmxo2_read_featbits (uint8_t *buffer) { - lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false); +static bool lcmxo2_read_featbits (uint8_t *buffer) { + return lcmxo2_execute_cmd(LSC_READ_FEABITS, 0, CMD_NORMAL, buffer, FEATBITS_SIZE, false); } -static void lcmxo2_refresh (void) { - lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false); +static bool lcmxo2_refresh (void) { + return lcmxo2_execute_cmd(LSC_REFRESH, 0, CMD_TWO_OP, NULL, 0, false); } static vendor_error_t lcmxo2_fail (vendor_error_t error) { @@ -346,20 +377,29 @@ static bool primer_check_rx_length (primer_cmd_e cmd, size_t rx_length) { static bool lcmxo2_init_featbits (void) { uint8_t programmed[2] = { 0x00, 0x00 }; uint8_t target[2] = { FEATBITS_0_SPI_OFF, FEATBITS_1_PROGRAMN_OFF }; - lcmxo2_read_featbits(programmed); + + if (lcmxo2_read_featbits(programmed)) { + return true; + } + if ((programmed[0] == target[0]) && (programmed[1] == target[1])) { return false; } + if (lcmxo2_erase_featbits()) { return true; } if (lcmxo2_write_featbits(target)) { return true; } - lcmxo2_read_featbits(programmed); + if (lcmxo2_read_featbits(programmed)) { + return true; + } + if ((programmed[0] != target[0]) || (programmed[1] != target[1])) { return true; } + return false; } @@ -403,7 +443,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons break; case CMD_GET_DEVICE_ID: - lcmxo2_read_device_id(buffer); + error = lcmxo2_read_device_id(buffer); tx_length = 4; break; @@ -416,7 +456,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons break; case CMD_RESET_ADDRESS: - lcmxo2_reset_flash_address(); + error = lcmxo2_reset_flash_address(); break; case CMD_WRITE_PAGE: @@ -424,7 +464,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons break; case CMD_READ_PAGE: - lcmxo2_read_flash_page(buffer); + error = lcmxo2_read_flash_page(buffer); tx_length = FLASH_PAGE_SIZE; break; @@ -437,7 +477,7 @@ void vendor_initial_configuration (vendor_get_cmd_t get_cmd, vendor_send_respons break; case CMD_REFRESH: - lcmxo2_refresh(); + error = lcmxo2_refresh(); hw_delay_ms(200); break; diff --git a/sw/tools/primer.py b/sw/tools/primer.py index 495413b..6bcb7e3 100644 --- a/sw/tools/primer.py +++ b/sw/tools/primer.py @@ -204,9 +204,16 @@ class STM32Bootloader: __connected = False - def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]): + def __init__( + self, + write: Callable[[bytes], None], + read: Callable[[int], bytes], + flush: Callable[[None], None], + progress: Callable[[int, int, str], None] + ): self.__write = write self.__read = read + self.__flush = flush self.__progress = progress def __append_xor(self, data: bytes) -> bytes: @@ -217,7 +224,7 @@ class STM32Bootloader: def __check_ack(self) -> None: response = self.__read(1) - if (response == None): + if (len(response) != 1): raise STM32BootloaderException('No ACK/NACK byte received') if (response == self.__NACK): raise STM32BootloaderException('NACK byte received') @@ -228,18 +235,22 @@ class STM32Bootloader: if (len(cmd) != 1): raise ValueError('Command must contain only one byte') self.__write(self.__append_xor(cmd)) + self.__flush() self.__check_ack() def __data_write(self, data: bytes) -> None: self.__write(self.__append_xor(data)) + self.__flush() self.__check_ack() def __data_read(self) -> bytes: length = self.__read(1) if (len(length) != 1): raise STM32BootloaderException('Did not receive length byte') - length = length[0] - data = self.__read(length + 1) + length = (length[0] + 1) + data = self.__read(length) + if (len(data) != length): + raise STM32BootloaderException('Did not receive requested data bytes') self.__check_ack() return data @@ -253,7 +264,10 @@ class STM32Bootloader: self.__cmd_send(b'\x11') self.__data_write(address.to_bytes(4, byteorder='big')) self.__data_write(bytes([length - 1])) - return self.__read(length) + data = self.__read(length) + if (len(data) != length): + raise STM32BootloaderException(f'Did not receive requested memory bytes') + return data def __go(self, address: int) -> None: self.__cmd_send(b'\x21') @@ -288,8 +302,12 @@ class STM32Bootloader: def connect(self, id: int) -> None: if (not self.__connected): - self.__write(self.__INIT) - self.__check_ack() + try: + self.__write(self.__INIT) + self.__flush() + self.__check_ack() + except STM32BootloaderException as e: + raise STM32BootloaderException(f'Could not connect to the STM32 ({e})') self.__connected = True dev_id = self.__get_id() if (dev_id != id): @@ -339,9 +357,16 @@ class LCMXO2Primer: DEV_ID_LCMXO2_7000HC = b'\x01\x2B\xD0\x43' - def __init__(self, write: Callable[[bytes], None], read: Callable[[int], bytes], progress: Callable[[int, int, str], None]): + def __init__( + self, + write: Callable[[bytes], None], + read: Callable[[int], bytes], + flush: Callable[[None], None], + progress: Callable[[int, int, str], None] + ): self.__write = write self.__read = read + self.__flush = flush self.__progress = progress def __cmd_execute(self, cmd: bytes, data: bytes=b'') -> bytes: @@ -355,14 +380,20 @@ class LCMXO2Primer: packet += data packet += crc32(packet).to_bytes(4, byteorder='little') self.__write(packet) + self.__flush() response = self.__read(5) if (len(response) != 5): raise LCMXO2PrimerException(f'No response received [{cmd}]') length = int.from_bytes(response[4:5], byteorder='little') - response += self.__read(length) - calculated_checksum = crc32(response) - received_checksum = int.from_bytes(self.__read(4), byteorder='little') + response_data = self.__read(length) + if (len(response_data) != length): + raise LCMXO2PrimerException(f'No response data received [{cmd}]') + checksum = self.__read(4) + if (len(checksum) != 4): + raise LCMXO2PrimerException(f'No response data checksum received [{cmd}]') + calculated_checksum = crc32(response + response_data) + received_checksum = int.from_bytes(checksum, byteorder='little') if (response[0:3] != b'RSP'): raise LCMXO2PrimerException(f'Invalid response token [{response[0:3]} / {cmd}]') @@ -371,16 +402,19 @@ class LCMXO2Primer: if (calculated_checksum != received_checksum): raise LCMXO2PrimerException(f'Invalid response checksum [{cmd}]') - return response[5:] + return response_data def connect(self, id: bytes) -> None: - primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID) - if (primer_id != self.__PRIMER_ID_LCMXO2): - raise LCMXO2PrimerException('Invalid primer ID received') + try: + primer_id = self.__cmd_execute(self.__CMD_GET_PRIMER_ID) + if (primer_id != self.__PRIMER_ID_LCMXO2): + raise LCMXO2PrimerException('Invalid primer ID received') - dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID) - if (dev_id != id): - raise LCMXO2PrimerException('Invalid FPGA device id received') + dev_id = self.__cmd_execute(self.__CMD_GET_DEVICE_ID) + if (dev_id != id): + raise LCMXO2PrimerException('Invalid FPGA device id received') + except LCMXO2PrimerException as e: + raise LCMXO2PrimerException(f'Could not connect to the LCMXO2 primer ({e})') def load_flash_and_run(self, data: bytes, description: str) -> None: erase_description = f'{description} / Erase' @@ -599,8 +633,8 @@ class SC64BringUp: write_timeout=self.__SERIAL_TIMEOUT ) - stm32_bootloader = STM32Bootloader(link.write, link.read, self.__progress) - lcmxo2_primer = LCMXO2Primer(link.write, link.read, self.__progress) + stm32_bootloader = STM32Bootloader(link.write, link.read, link.flush, self.__progress) + lcmxo2_primer = LCMXO2Primer(link.write, link.read, link.flush, self.__progress) stm32_bootloader.connect(stm32_bootloader.DEV_ID_STM32G030XX) stm32_bootloader.load_ram_and_run(self.__sc64_update_data.get_primer_data(), 'FPGA primer -> STM32 RAM') @@ -645,7 +679,7 @@ if __name__ == '__main__': sc64_bring_up = SC64BringUp(progress=utils.progress) Utils.log() - Utils.info('[ Welcome to SC64 flashcart board bring-up! ]') + Utils.info('[ Welcome to SummerCart64 flashcart board bring-up! ]') Utils.log() Utils.log(f'Serial port: {port}') @@ -683,6 +717,7 @@ if __name__ == '__main__': original_sigint_handler = signal.getsignal(signal.SIGINT) try: signal.signal(signal.SIGINT, lambda *kwargs: utils.exit_warning()) + Utils.log('Starting SC64 flashcart board bring-up...') sc64_bring_up.start_bring_up(port, bootloader_only) except (serial.SerialException, STM32BootloaderException, LCMXO2PrimerException, SC64Exception) as e: if (utils.get_progress_active):