[SC64][SW] Added very basic SDRAM test in the primer before flashing bootloader

This commit is contained in:
Mateusz Faderewski 2024-03-17 02:04:05 +01:00
parent f27f644a7e
commit c156b72bee
2 changed files with 110 additions and 20 deletions

View File

@ -6,7 +6,9 @@
- [**Putting it together**](#putting-it-together)
- [**Initial programming**](#initial-programming)
- [**Troubleshooting**](#troubleshooting)
- [*`primer.py` threw error on `Bootloader -> SC64 FLASH` step*](#primerpy-threw-error-on-bootloader---sc64-flash-step)
- [*`primer.py` threw `No SC64 USB device found` error*](#primerpy-threw-no-sc64-usb-device-found-error)
- [*`primer.py` threw `SDRAM test error...` message*](#primerpy-threw-sdram-test-error-message)
- [*`primer.py` threw other error message*](#primerpy-threw-other-error-message)
---
@ -115,9 +117,23 @@ Congratulations! Your SC64 flashcart should be ready for use!
### **Troubleshooting**
#### *`primer.py` threw error on `Bootloader -> SC64 FLASH` step*
#### *`primer.py` threw `No SC64 USB device found` error*
This issue can be attributed to incorrectly programmed FT232H EEPROM in the first programming step.
Check again in `FT_PROG` application if device was configured properly.
Make sure default FTDI drivers are installed for the SC64 in the device manager (only on Windows OS).
Make sure you have correct access to `/dev/ttyUSBx` device and `ftdi_sio` and `usbserial` modules are loaded (only on Linux OS).
#### *`primer.py` threw `SDRAM test error...` message*
This issue shows up when there's a problem with the connection to the SDRAM chip or the chip itself is malfunctioning.
Check for any solder bridges and unconnected pins on U8/U9 chips.
Once FPGA and microcontroller has been programmed successfully `primer.py` script needs to be run in special mode.
Please use command `python3 primer.py COMx sc64-firmware-{version}.bin --bootloader-only` to try programming bootloader again.
Please use command `python3 primer.py COMx sc64-firmware-{version}.bin --bootloader-only` to test SDRAM again and continue bootloader programming process.
#### *`primer.py` threw other error message*
Due to multiple possible causes of the problem it's best to start visually inspecting SC64's board for any defects, like bad solder work or chips soldered backwards.
If visual inspection didn't yield any obvious culprits then next step would be to check if everything is connected correctly.
Check if TX/RX signals aren't swapped and if SC64 is getting power from the USB cable. Best place to check supply voltage are the exposed test pads on the left of U8 chip.
If everything at this point was checked and looked fine, then feel free to open new thread in the [*Discussions*](https://github.com/Polprzewodnikowy/SummerCart64/discussions) tab.
Make sure to describe your problem extensively, attach SC64 board photos **from the both sides**, and paste all logs/screenshots from the `primer.py` output.

View File

@ -5,10 +5,11 @@ import os
import queue
import serial
import signal
import struct
import sys
import time
from binascii import crc32
from enum import IntEnum
from enum import IntEnum, StrEnum
from serial.tools import list_ports
from sys import exit
from typing import Callable, Optional
@ -478,6 +479,8 @@ class SC64:
__serial: Optional[serial.Serial] = None
__packets = queue.Queue()
SDRAM_SIZE = 64 * 1024 * 1024
class __UpdateStatus(IntEnum):
MCU = 1
FPGA = 2
@ -485,7 +488,8 @@ class SC64:
DONE = 0x80
ERROR = 0xFF
def __init__(self) -> None:
def __init__(self, progress: Callable[[int, int, str], None]) -> None:
self.__progress = progress
SC64_VID = 0x0403
SC64_PID = 0x6014
SC64_SID = "SC64"
@ -575,14 +579,36 @@ class SC64:
return packet
return None
def update_firmware(self, data: bytes) -> None:
def __cmd_state_reset(self) -> None:
self.__execute_command(b'R')
def __cmd_memory_read(self, address: int, length: int) -> bytes:
return self.__execute_command(b'm', [address, length])
def __cmd_memory_write(self, address: int, data: bytes) -> None:
self.__execute_command(b'M', [address, len(data)], data)
def __cmd_firmware_update(self, address: int, length: int) -> None:
self.__execute_command(b'F', [address, length])
def update_firmware(self, data: bytes, description: str) -> None:
FIRMWARE_ADDRESS = 0x00100000
FIRMWARE_UPDATE_TIMEOUT = 90.0
STEPS = 6
self.__progress(STEPS, 0, description)
self.__reset()
self.__execute_command(b'R')
self.__execute_command(b'M', [FIRMWARE_ADDRESS, len(data)], data)
self.__execute_command(b'F', [FIRMWARE_ADDRESS, len(data)])
self.__progress(STEPS, 1, description)
self.__cmd_state_reset()
self.__progress(STEPS, 2, description)
self.__cmd_memory_write(FIRMWARE_ADDRESS, data)
self.__progress(STEPS, 3, description)
self.__cmd_firmware_update(FIRMWARE_ADDRESS, len(data))
self.__progress(STEPS, 4, description)
timeout = time.time() + FIRMWARE_UPDATE_TIMEOUT
while True:
@ -596,11 +622,62 @@ class SC64:
if (id != b'F'):
raise SC64Exception('Unexpected packet id received')
status = self.__UpdateStatus(int.from_bytes(packet_data[0:4], byteorder='big'))
if (status == self.__UpdateStatus.ERROR):
raise SC64Exception('Firmware update error')
if (status == self.__UpdateStatus.DONE):
if (status == self.__UpdateStatus.BOOTLOADER):
self.__progress(STEPS, 5, description)
elif (status == self.__UpdateStatus.DONE):
self.__progress(STEPS, 6, description)
time.sleep(2)
break
elif (status == self.__UpdateStatus.ERROR):
raise SC64Exception('Firmware update error')
class __RamTestPattern(StrEnum):
OWN_ADDRESS = 'own address'
ALL_ZEROS = 'all zeros'
ALL_ONES = 'all ones'
RANDOM_DATA = 'random data'
def __create_ram_test_pattern(self, pattern: __RamTestPattern) -> bytes:
if (pattern == self.__RamTestPattern.OWN_ADDRESS):
addresses = list(range(0, self.SDRAM_SIZE, 4))
data = struct.pack(f'>{len(addresses)}I', *addresses)
elif (pattern == self.__RamTestPattern.ALL_ZEROS):
data = b'\x00' * self.SDRAM_SIZE
elif (pattern == self.__RamTestPattern.ALL_ONES):
data = b'\xFF' * self.SDRAM_SIZE
elif (pattern == self.__RamTestPattern.RANDOM_DATA):
data = os.urandom(self.SDRAM_SIZE)
return bytes(data)
def sdram_test(self, description: str) -> None:
CHUNK_LENGTH = 1 * 1024 * 1024
self.__reset()
self.__cmd_state_reset()
for pattern in self.__RamTestPattern:
write_description = f'{description} / Write {pattern.value}'
check_description = f'{description} / Check {pattern.value}'
test_data = self.__create_ram_test_pattern(pattern)
self.__progress(self.SDRAM_SIZE, 0, write_description)
for offset in range(0, self.SDRAM_SIZE, CHUNK_LENGTH):
self.__cmd_memory_write(offset, test_data[offset:offset+CHUNK_LENGTH])
self.__progress(self.SDRAM_SIZE, offset + CHUNK_LENGTH, write_description)
self.__progress(self.SDRAM_SIZE, 0, check_description)
for offset in range(0, self.SDRAM_SIZE, CHUNK_LENGTH):
check_data = self.__cmd_memory_read(offset, CHUNK_LENGTH)
if (check_data != test_data[offset:offset+CHUNK_LENGTH]):
for chunk_offset in range(0, CHUNK_LENGTH, 4):
test_address = offset + chunk_offset
expected_value = int.from_bytes(test_data[test_address:test_address+4], byteorder='big')
read_value = int.from_bytes(check_data[chunk_offset:chunk_offset+4], byteorder='big')
if (read_value != expected_value or test_address == 0x00100000):
raise SC64Exception(f'SDRAM test error at 0x{test_address:08X}: read 0x{read_value:08X} != expected 0x{expected_value:08X}')
self.__progress(self.SDRAM_SIZE, offset + CHUNK_LENGTH, check_description)
class SC64BringUp:
@ -621,7 +698,7 @@ class SC64BringUp:
def start_bring_up(self, port: str, bootloader_only: bool=False) -> None:
link = None
sc64 = SC64()
sc64 = SC64(self.__progress)
try:
if (not bootloader_only):
@ -651,11 +728,8 @@ class SC64BringUp:
time.sleep(self.__INTERVAL_TIME)
link.read_all()
bootloader_description = 'Bootloader -> SC64 FLASH (no progress reporting)'
bootloader_length = len(self.__bootloader_only_firmware)
self.__progress(bootloader_length, 0, bootloader_description)
sc64.update_firmware(self.__bootloader_only_firmware)
self.__progress(bootloader_length, bootloader_length, bootloader_description)
sc64.sdram_test('SC64 SDRAM test')
sc64.update_firmware(self.__bootloader_only_firmware, 'Bootloader -> SC64 FLASH')
finally:
if (link and link.is_open):
link.close()