STM32 based SD card driver for C64


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.

Concept

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)

Implementation

This is the address decoder part:


The first unit decodes PHI1=1 and I/O1=0, so the output Y3 will be low when the CPU reads or writes the I/O1 area. The second unit decodes the A0 and R/W signals, producin the following low pulses:
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
Now let's have a look at the other side. This is the microcontroller's code:
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;
}

Daughter boards and assembly


Click to enlarge
In this prototype I used some complete boards instead of just parts. Why? Because they are cheap and available in the online stores. Soldering them is also a bit simpler than would it be for SMD parts.

The STM32 board is the one called blue-pill. Widely available and costs arount 1.6 USD.

The SD card socket is also a cheap module, less than 1 USD.

Both can be connected to other boards just via standard 2.54mm PIN holes.

The 28C64 EEPROM is in a socket, that is required, so the IC can be removed for firmware upgrade. The firmware in the blue-pill also upgradeble via the programmer port, located on the upper-left corner.

Limitations

Although the STM32 chip is a little strong bastard, I has some limitations so my design does. It only has 64K flash and 20K of RAM, this limits the number of directory entries can be cached. The C64 display only has 40 characters horizontally, this is also a limit I needed to consider. So for now these matter.
  • Only FAT16 and FAT32 supported
  • No long filenames, just standard old DOS 8.3 name style is allowed. This can be painful, when a lots of files have similar names in a folder.
  • One folder can only hold 1024 file entries. If it has more, the firmware omits the rest
  • Only PRG files supported
  • This card is not a 1541 emulator, so games using disks and multiple files are not supported


Will all the games load and run?

I would not guarantee this. For example long files which reach the I/O area of the C64 may overwrite I/O registers. Obviously this is a small logical bug, which will be corrected in the firmware later. But other tricky things can happen. I have seen many custom loader and codes that for example writes directly into the CPU stack. Investigating all of those unique pitfalls may take a while. But again, since the firmware is upgradable, all of these things can be improved and fixed later. All in all I am happy with the result as it is now. Most of my favourite games load and run. They do quickly.

See how it works

I have created a little video to show the basic funcionality of the card. Please note, this is the first version, I used a mobile phone to make the video and I am not a professional video editor. Anyway, I hope you will see what the point is.


https://youtu.be/6DKwfDgT_E4



Interested?

You can find a mail address at the end of the video, so you can write me a mail. I usually reply ... ehhh... sooner or later.

joco