6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue May 07, 2024 6:45 pm

All times are UTC




Post new topic Reply to topic  [ 26 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Nov 09, 2015 4:37 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
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:

  1. Configure the hardware by writing to the control register and the divider register(s) to establish operating parameters
  2. Spin on the status register until the idle bit goes high
  3. Write to the data register
  4. (optional if reading) Spin on the status register until the idle bit goes high
  5. (optional if reading) Read from the data register
  6. 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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 5:43 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1685
Location: Sacramento, CA
This would be a great addition to the IO device list. My 65SPI works well but the Xilinx 95xx chips are getting harder to find. If you are looking for some ideas for features, download the datasheet for the 65SPI and take a look. The features I included were the result of comments from 6502.org users back when I was creating it. There's probably some discussions in the group here somewhere as well.

https://sbc.rictor.org/65spi1.html

Good luck!

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Last edited by 8BIT on Sat Jun 27, 2020 8:55 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 5:59 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8176
Location: Midwestern USA
jmp(FFFA) wrote:
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

Suggestion: make the status register "idle" bit bit 7 so the BIT instruction can be followed by a BMI if the bit is set or BPL if the bit is cleared. The code will slightly shrink and be nore efficient. For example:

Code:
SPI      =$C400
;
;
;   setup...
;
         LDA #CONFIG
         STA SPI               ;config register
         LDA #<CLKDIV
         STA SPI+2             ;LSB of clock divider
         LDA #>CLKDIV
         STA SPI+3             ;MSB of clock divider
;
;
;   you forgot to initialize .X
;
         LDX #0
;
;
;   main loop...
;
NEXT     BIT SPI               ;check idle bit
         BPL NEXT              ;busy
;
         LDA INPUT,X           ;SPI transmit buffer
         STA SPI+1
;
L1       BIT SPI               ;check idle bit
         BPL L1                ;no data
;   
         LDA SPI               ;get datum & store in...
         STA OUTPUT,X          ;SPI receive buffer
         INX
         CPX #LEN
         BCC NEXT
;

You really need to do this with interrupts, since transmission and reception are two unrelated activities. The same principles used in UART driver code will work here.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 6:08 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
In addition to a bit for clock polarity, you also need a bit for clock edge. See https://en.wikipedia.org/wiki/Serial_Pe ... de_numbers


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 6:12 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Quote:
For write-only devices, steps 4 and 5 may be safely omitted.

And for read/write or read-only devices, step 2 may be omitted, because the device was idle in previous step 4.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 8:07 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
BigDumbDinosaur wrote:
Suggestion: make the status register "idle" bit bit 7 so the BIT instruction can be followed by a BMI if the bit is set or BPL if the bit is cleared. The code will slightly shrink and be nore efficient.

Bit 6 can also be tested directly with the BIT instruction. Bit 7 is usually for IRQ, to quickly poll 65xx I/O ICs to see who interrupted. If the "idle" bit is separate, it could go on bit 6. I second Daryl's motion though that his 65SPI be considered, so the resulting design will have little or no incompatibility with it, if possible. I bought a half-dozen but have not used them yet.

Quote:
You really need to do this with interrupts, since transmission and reception are two unrelated activities. The same principles used in UART driver code will work here.

Unlike UARTs, SPI always transmits and receives simultaneously. When 8 bits are shifted out, 8 are also shifted in at the same time, bit for bit. With the SPI devices I've used, one or the other is usually insignificant, meaning that when you're transmitting, the data coming in at the same time is meaningless and can be dumped; and when you're receiving, the outgoing data is "don't care" or zeros or something like that. That's not always the case, but seems to be most common. Since the master controls the shift clock, there won't be any surprises about data coming in out of the blue; but the interrupt will sometimes be advantageous so you don't have to poll to see when 8 bits are done getting shifted. However if the product does not have to be the master (ie, can also be a slave), the interrupt definitely is needed, to tell when a remote master did a byte transfer.

jmp(FFFA), be sure to see our 65SIB (not to be confused with Daryl's 65SPI) spec at viewtopic.php?t=1064&start=105 . It is compatible with SPI, but more flexible. A couple of the paragraphs there say:

      65SIB, or 6502.org Serial Interface Bus, is a synchronous-serial bus which, although geared primarily around SPI (and QSPI), can also be used for Microwire devices, daisy chains of dumb shift registers like the 4094, 4021, 74HC165, and 74HC595 (which allow hundreds or conceivably even thousands of bits of I/O at a single 65SIB address), as well as for 3- and 4-wire synchronous-serial interfaces that are SPI-like but different enough that they can't actually be called SPI. All these similar interface types can be mixed on 65SIB, with your controller software knowing how to communicate with each device.

      <snip>

      65SIB takes the SPI and similar interfaces and makes them an external bus, similar in purpose to IEEE-488 (HP-IB or GPIB). 65SIB aims to make it easier to share designs and conceivably even hardware. It is much more friendly for cobbling together small projects, making your own equipment to be controlled by your 6502 (or other) home-made computer. It specifies a standard connector and other characteristics for compatibility across many synchronous-serial device types. The data transfer protocols are mostly specified in the data sheets of individual ICs you wish to connect. With the addition of the CONF\ (configuration) line, 65SIB allows higher complexity levels of plug-and-play, nested sub-buses, and the like (which have not been thoroughly defined yet), but does not require such complexity levels, and indeed they can be totally ignored by basic users.

Daryl put a 65SIB port on one of the SBCs he sells, and I have one on my workbench computer which I have used a little, for a graphic LCD and a flash memory.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 3:24 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
Thank you everyone for the comments and suggestions.

I've setup a wiki page for the specifications and temporarily hosted it here: https://github.com/jason6502/pic-uart/wiki/PIC-SPI-Specification

Once I setup a new repository for the pic-spi project, I'll move the page there.

For the initial implementation, I'm going to support master mode only. However, I'm keeping slave mode in mind and attempting to plan for it. Since the PIC includes an SPI peripheral built-in, I'm not going to try to support anything more general at this time. More general shift-register support could be implemented with bit-banging, however this would be quite a bit slower than what the hardware SPI peripheral is capable of. While its true that the PIC could be programmed to use the SPI peripheral when SPI mode was enabled, and switch to bit-banged mode when it was not enabled, I prefer to get to the finish line quickly with the key functionality working and then let others expand on my work if they desire.

I'm looking at Daryl's 65SPI datasheet now (nicely done, BTW). There are some hardware differences between the PIC and the CPLD Daryl used which will impact compatibility between the two devices. In particular, the PIC will only support a maximum of 4 slave devices due to the limited number of pins on the 28-pin device (as opposed to 8 slave devices for Daryl's 65SPI). Also, I plan to support slave mode in the future. Where we have bits in common in the status and control registers, I will go ahead and align them to minimize any code changes required. I'll also look carefully at any differences between what I'm planning and what Daryl already has and consider whether to incorporate these differences as well.

If high 6502/65816 bus speeds are to be used with this device, I expect using it in interrupt mode will be mandatory. In polled mode, I expect to see limits of about 6-8 MHz unless steps are taken to reduce the rate the registers are polled. This has to do with the maximum rate at which the PIC can update its state internally not being high enough to keep up with a fast 6502/65816.

Finally, I'll try to put together a nice datasheet like Daryl has done in PDF format for the PIC-SPI when the design has stabilized a bit.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 5:14 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 485
Location: Switzerland
Congrats, very nice project. Now I have question to the hardware, how do you now interface the 6502 to the PIC? I have continuously read the thread with the PIC as UART, but at the end it was not clear to me which circuit you are currently using as the GLUE. Do you have a schematic?


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 6:15 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
cbscpe wrote:
Do you have a schematic?

Have you had a look here: http://forum.6502.org/viewtopic.php?f=4&t=3476

That shows the schematic of the test system I'm using. I'm connecting the PIC to the 6502 almost the same way that the MC6850 is connected. The exceptions are that the PIC does not need a clock source and that I'm currently using voltage conversion circuitry (a 74LVX4245) to convert from 5V to 3.3V on the data lines.

To be more specific, the following connections are made between the 6502 and the PIC:

A0-A1: address lines
RWB: read strobe
WRB: write strobe
D0-D7: data lines (currently via a 74LVX4248)
CS: chip select
IRQ: interrupt line

That is the sum total of all of the connections between the 6502 and the PIC at present.

As part of the datasheet which I will put together for the PIC-SPI, I will include some "application information" showing the specifics of connecting the PIC to a "typical" 8-bit CPU bus (of course I'll use a 65C02 as the typical 8-bit CPU).

P.S. If anything still isn't clear, let me know and I can draw you a schematic of the relevant connections.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 6:54 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 485
Location: Switzerland
No wait states?


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 09, 2015 7:46 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
cbscpe wrote:
No wait states?

Depends on your bus speed. I've found they are not necessary with the PIC PMP peripheral at speeds up to approximately 8 MHz (the highest I've tested so far).

There are two timing-related limits to be aware of.

The first is the bus timing limitations. This is the maximum speed at which the PMP peripheral on the PIC can safely operate. Specifications notwithstanding, I've had no problems running up to 8 MHz here.

The second limitation is the rate at which the PIC system software can update internal state. So, for example, if you are writing to the PIC-UART and polling the status in between each write to see if the PIC-UART is ready for another character, the maximum rate at which you can do this is limited to the maximum rate at which the PIC software can update the register you are reading to reflect the new status. At least for my PIC-UART implementation, this occurs around 5 MHz right now. Adding wait states does not noticeably affect this number. Reducing the rate at which you poll (e.g. by adding NOPs) will resolve the problem, as will using interrupts because then the PIC controls the timing not the CPU. I expect similar limits will exist on the PIC-SPI, though somewhat higher because the system state is simpler too.

I will update the schematics for my 6502 Test System thread this evening for you and include the wait state generator I'm sometimes using with it. I think the only changes are to the second page of the schematic. It still shows an MC6850 in the system, but the differences are minimal for the PIC connection as in my previous post.


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 10, 2015 3:11 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
jmp(FFFA) wrote:
I will update the schematics for my 6502 Test System thread this evening for you and include the wait state generator I'm sometimes using with it.

Well, it looks like properly updating the schematics for the 6502 Test System is going to be a bigger job than I expected. Instead, I refer you to what is up on the test system thread http://forum.6502.org/viewtopic.php?f=4&t=3476 along with this schematic of the wait state generator I'm using (well, I'm actually using a 74HC107, but the circuit is nearly the same):

Attachment:
File comment: Wait State Generator
IMG_20151109_213559~2.jpg
IMG_20151109_213559~2.jpg [ 377.62 KiB | Viewed 1021 times ]


I will eventually put the schematics for the test system into Altium Designer when it has stopped changing weekly. Actually, I've just ordered several tubes of GALs to replace most of the 74HC chips with. Had I realized these were still available in DIP form earlier, I would have saved myself a lot of headaches with the 74HC logic, but I guess using them is a sort of right-of-passage. :) I just hope the GALs don't cause the same kinds of ground bounce problems some other non-HC logic families do on breadboards.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 11, 2015 7:23 am 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 485
Location: Switzerland
Note that GALs are power hungry. A 7ns GAL22V10 draws almost 100mA. I use GALs a lot and never had any issues on breadboards with them. I think you are in a better situation than with AC logic. As for my question regarding wait states. I was actually thinking that you have implemented some sort of variable wait state generator that automatically adopts to different clock speeds of the 6502 and the MCU. In other words some wait-state generator that starts when the PIC-IO is selected and stops when PIC gives out some "done" signal. The reason is that I would also like to use MCUs that do not have a PMP and much higher clockrates on the 6502 side. So I think I have to come up with my own solution for this.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 11, 2015 12:45 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
cbscpe wrote:
Note that GALs are power hungry. A 7ns GAL22V10 draws almost 100mA. I use GALs a lot and never had any issues on breadboards with them. I think you are in a better situation than with AC logic.

I'm sticking with 15ns 22V10s. I'm aware that they are a bit power hungry, and will avoid them for battery operation.

cbscpe wrote:
The reason is that I would also like to use MCUs that do not have a PMP and much higher clockrates on the 6502 side.

The PIC-SPI should work at much higher clock rates (14 MHz+) so long as you use it with interrupt driven I/O. Or if you really want to use it with polled mode, you'll need to add some NOPs to your polling loop to account for the latency involved in updating the state machine. If you use an MCU without something like the PMP, I think you'll find that you'll need to add a LOT of wait states which will seriously impact processor performance while doing I/O at high speeds.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 11, 2015 2:13 pm 
Offline
User avatar

Joined: Sun Oct 13, 2013 2:58 pm
Posts: 485
Location: Switzerland
If you use 15ns GALs then you could look for Quarter Power GALs they are quite efficient and consume only 55mA worst case. I really doubt that the performance impact of many wait states for the IO register data cycle is relevant to the overall system performance. I'd really want to measure that and compare it to a solution that uses a 65C22 as interface between the 6502 bus and the AVR and needs to poll for ready. On the other hand I still have this idea in mind to convert Daryls SPI using Xilinx 95xx to an ATF1504AS. That would be definitively the fastest solution.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 26 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: