Click to enlarge |
The aim of this project is a C64 interface card, which is able to read and load files from SD card. Since C64 is a de-facto retro
platform today, this mainly means loading games. I do not want to compete with other great projects, such as SD2IEC or 1541 EMU which
are already available. Only wanted to have a solution to load and play games in a simple way. Price was also a factor, so this is why
I used daughter boards, which cost cents.
And this is it. Keep as simple as possible. This card is a prototype. I used cheap parts and cheap modules that anyone can buy on the online market places. The heart of the card is an STM32F103 microcontroller, which handles the FAT filesystem on the SD card, can read folders and files and can accept basic file handling commands from the C64. In this scenario C64 is the HOST, while STM32 is a DEVICE. I order to send commands to the DEVICE, the HOST needs a little firmware, a software to implement a plain file browser application. This code is stored an EEPROM chip and the solution is the same as for any ordinary C64 EPROM card. The firmware is located at the address $A000..$BFFF and activated during the C64 RESET cycle. The STM32 microcontroller also has a firmware. It uses the freely available FatFS module for the SD card file system, and provides a simplified commandset to the C64 HOST to read and write files and folders (such as open, read, readdir etc.). The first version of the firmware only implements directory browsing and file loading though. This is what most people need: find a game, load it in seconds, then play. |
See the concept above. This is the simplfied logical diagram of the card. The microcontroller communicates both with the C64 and
the SD card via SPI interfaces. For the C64 this SPI interface is formed by two shift registers (74HC595 and 74HC165). The HOST can read
and write these registers by acccessing the I/O1 memory area at $DE00. For handshaking there is a REQuest and ACKnowledge signal.
REQ is set when the HOST initiates a communication and remains 1, until the micocontroller clears it with the ACK signal.
This simple handshanking functinality is implemented by a D-type flip-flop (HC74)
The first flip-flop is the REQ signal. Whenever CPU does a write to $DE00, this will be set (the rising edge of the W0 will set the flip-flop).
The microcontroller polls the value of the REQ line, so it knows that when REQ goes 1, a new byte needs to be transferred.
MCU now does an SPI send/receive, then clears the flip-flop by pulling the ACK signal to low.
The staus of the REQ is also readable by the CPU at $DE01. So the CPU can detect, when the actual transfer is done.
So this is how the C64 can send or receive a byte. See the actual 6502 code below.
The second flip-flop controls the EEPROM. During the reset cycle it is cleared, so the EXROM will be 0. If EXROM is 0, the C64 will use the ROML signal to access the external memory. EXROM is connected to the CE signal of the 28C64 while the ROML is connected to the OE. Therefore the EEPROM will be active only when both are low. Any value written to the address $DE01 will set EXROM, so from that point on the EEPROM is removed from the address space. This is done by the C64 firmware, when the loaded app or game is started. |
Let's have a look at the shift regsiters. This is quite simple though. The upper HC595 unit it the receiver
register, it is written over the serial interface by the microcontroller (MOSI and SCK signals). The RCK is also controlled by
the microcontroller, it stores the shift register value inside the HC595. This register is read by C64 on the paralell output
interface, controlled by signal R0. A single read at $DE00 will provide the value sent by the microcontroller.
HC165 is the sender shift register. CPU writes this at $DE00 , using the parallel input interface and signal W0 for the write strobe. The value then shifted out on the serial output interface to the microcontroller (MISO and SCK signals). It is important to note that during the SPI tranfer the microcontroller is the Master and these registers form the Slave SPI device. So the C64 initiates the communication, this is sensed by the microcontroller (REQ signal), then the microcontroller does one SPI cycle, and clears the REQ signal. CPU sends a byte to the sender register, then waits until the REQ signal is cleared, then reads the receiver register. The REQ signal is mapped to the bit #7 at $DE01, this is not shown the image, but there is a one gate HC125 chip on the card enabled by R1. See the code to make it clear. Simple, I told you. ; send and receive one byte sendrecv: sta $de00 ; send byte to STM32 srw0: lda $de01 ; wait for ACK signal bmi srw0 lda $de00 ; read the reply rts byte SendRecv(byte d) { byte r; while ((GPIOB->IDR & PIN_REQ)!=PIN_REQ); // wait for REQ signal from C64 r=SPI(d); // send a byte to C64, got byte from C64 GPIO_SetBits(GPIOB,PIN_RCK); // rck H GPIO_ResetBits(GPIOB,PIN_RCK); // rck L GPIO_ResetBits(GPIOB,PIN_ACK); // ack L GPIO_SetBits(GPIOB,PIN_ACK); // ack H return r; } |