I'm still in the midst of testing for my PIC-based MC6850 replacement, but my thoughts have started to turn to leveraging the work done on that project to create another bus-based peripheral to provide SPI connectivity.
Since this is not being based on any existing piece of hardware like the MC6850 replacement was, there is some room for planning here. Here are the high level details for what I'm considering at the moment:
- One 8-bit control register (write only)
- One 8-bit status register (read only)
- One 8-bit data register (bidirectional)
- One or two 8-bit clock divider register(s) (bidirectional)
The SPI protocol is bidirectional and always initiated by the master, so the CPU would use it as follows:
- Configure the hardware by writing to the control register and the divider register(s) to establish operating parameters
- Spin on the status register until the idle bit goes high
- Write to the data register
- (optional if reading) Spin on the status register until the idle bit goes high
- (optional if reading) Read from the data register
- Loop back to step 2 until all bytes have been written/read
For write-only devices, steps 4 and 5 may be safely omitted.
Here's some sample 6502 code for operating in polled mode:
Code:
SPI = $C400
; Step 1
LDA #CONFIG
STA SPI ; config register
LDA #<CLKDIV
STA SPI+2 ; LSB of clock divider
LDA #>CLKDIV
STA SPI+3 ; MSB of clock divider
; Step 2
NEXT LDA SPI ; status register
BIT #1 ; idle bit
BEQ NEXT
; Step 3
LDA INPUT,X ; data to send to SPI device
STA SPI+1
; Step 4
1 LDA SPI ; status register
BIT #1 ; idle bit
BEQ 1B
; Step 5
LDA SPI
STA OUTPUT,X ; data received from SPI device
; Step 6
INX
CPX #LEN
BCC NEXT
An interrupt mode would also be provided as well.
I/O would be byte oriented, making it difficult to communicate with devices that expect a non-byte-aligned number of bits. However, I do not believe such devices are common. If I am wrong, then some accommodation can be made with the control register.
For the status register, I'm thinking of allocating the bits something like this:
- 1 bit for idle status
- n bits for additional status (errors)
- m bits for device ID (to identify interrupting device)
For the control register, I'm thinking of allocating the bits something like this:
- 1 bit for clock polarity
- m bits for up to 2^m chip selects (only 1 can be active at a time)
There are a lot of SPI devices out there and I've only used a small number of them. If there is any functionality I've left out which would be useful to have for a general purpose SPI interface, please let me know your suggestions and I'll try to incorporate them into the final design. Given that I already have a test system and framework (PIC-UART) to build this on, I'm hoping it will come together pretty quickly. I'll plan to test the completed system out with some serial memory in order to exercise the hardware for both sending and receiving.