I have a 4550 setup for SPI slave mode. The system it's connected to (Playstation) has a Slave Select type line, but the slave mode I selected ignores the SS line; I've been watching it manually.
The clock line is at rest high, and drops low eight times per byte, like so:
----__--__--__--__-- __--__--__--__----------
There is 20us from the time the Slave Select style line goes low until the first drop of the clock, and the clock does not move if the Slave Select line is high.
The first byte sent from the console is 10000000; first bit high, rest are low. The transmission looks like this:
----__--__--__--__-- __--__--__--__----------
--------__________________________________
The slave select line goes down for the duration of the transmission. With the oscope set to trigger on the falling edge of the slave select line, the transmission looks like this:
-_____________________________________------------
----__--__--__--__-- __--__--__--__------------------
--------_______________________________------------
From seeing the number of clock drops (8) and when the console changes the output (falling edge of clock), I know the SPI should be reading the bit on the rising edge, and changing the output on falling edge.
This matches figure 19-5 in the datasheet, using SMP=0, CKE=0, and CKP=1, and SPI mode 0101 (slave mode, ignore slave select pin). The setup of the SPI module is done in C18 with SSPSTAT=0x00; SSPCON1=0x35;
I have the PIC waiting for the slave select line to drop, then opening the SPI module, writing the byte to be transmitted to SSPBUF (sending out the last byte read in, unless it is 0, then sending out 0x99 instead), waiting for the BF flag, saving the byte read, and closing the SPI module. That's it.
Since the last byte read is always for some reason 0x00, I am always sending out 0x99, which helps me see when the shift register is doing stuff. Frankly, the outgoing byte is PERFECT. But for some reason, the byte being read is always read as 0x00, as if the first bit is being ignored, or an additional bit is being read in shifting out the first.
The code is posted below, and is very simple. If anyone can help me spot where I'm making the mistake, I would serious love to hear it.
The pattern I see on my oscope including the outgoing 0x99, is below. Sorry for the ASCII art, but digital images of my oscope done seem to work too well.
PSX header file
PSX C file
The clock line is at rest high, and drops low eight times per byte, like so:
----__--__--__--__-- __--__--__--__----------
There is 20us from the time the Slave Select style line goes low until the first drop of the clock, and the clock does not move if the Slave Select line is high.
The first byte sent from the console is 10000000; first bit high, rest are low. The transmission looks like this:
----__--__--__--__-- __--__--__--__----------
--------__________________________________
The slave select line goes down for the duration of the transmission. With the oscope set to trigger on the falling edge of the slave select line, the transmission looks like this:
-_____________________________________------------
----__--__--__--__-- __--__--__--__------------------
--------_______________________________------------
From seeing the number of clock drops (8) and when the console changes the output (falling edge of clock), I know the SPI should be reading the bit on the rising edge, and changing the output on falling edge.
This matches figure 19-5 in the datasheet, using SMP=0, CKE=0, and CKP=1, and SPI mode 0101 (slave mode, ignore slave select pin). The setup of the SPI module is done in C18 with SSPSTAT=0x00; SSPCON1=0x35;
I have the PIC waiting for the slave select line to drop, then opening the SPI module, writing the byte to be transmitted to SSPBUF (sending out the last byte read in, unless it is 0, then sending out 0x99 instead), waiting for the BF flag, saving the byte read, and closing the SPI module. That's it.
Since the last byte read is always for some reason 0x00, I am always sending out 0x99, which helps me see when the shift register is doing stuff. Frankly, the outgoing byte is PERFECT. But for some reason, the byte being read is always read as 0x00, as if the first bit is being ignored, or an additional bit is being read in shifting out the first.
The code is posted below, and is very simple. If anyone can help me spot where I'm making the mistake, I would serious love to hear it.
The pattern I see on my oscope including the outgoing 0x99, is below. Sorry for the ASCII art, but digital images of my oscope done seem to work too well.
Code:
-_____________________________________------------ Slave Select line
----__--__--__--__-- __--__--__--__------------------ clock
--------_______________________________------------ data in to PIC
--------________---------________-------------------- data out from PIC
Code:
#ifndef PSX_H
#define PSX_H
#define PSX_ATT PORTAbits.RA5
#define PSX_CLOCK PORTBbits.RB1
//OpenSPI(SLV_SSON, MODE_10, SMPMID);
/* Okay, so using the OpenSPI function just aint cutting it. Tryng to manually start the SPI module
SSPSTAT =0x00;
7 - Sample bit - off. 'must be cleared when SPI is used in Slave mode'
6 - CKE - off. Datasheet figure 19-5, CKP=1, CKE=0 matches what we want.
5-0 - read only
SSPCON1 = 0x35;
7 - WCOL - Clear to be safe
6 - Receive overflow - clear to be safe
5 - SSPEN - on, main enable bit
4 - CKP - on (we want CKP=1, CKE=0)
3-0 - Port mode select bits
0100 and 0101 are the only slave modes. 0100 has the SPI
module control the SlaveSelect line. *WE* want to control
that, so use mode 0101.
*/
#define PSX_OPENSPI { SSPSTAT =0x00; SSPCON1 = 0x35; }
#define PSX_CLOSESPI { SSPCON1 &= 0b11011111; }
// Prototypes
void PSX_Init_Pins(void);
void PSX_DIG_main (void);
#endif //PSX_H
PSX C file
Code:
#include <p18cxxx.h>
#include "psx.h"
#include "upcb.h"
#include <spi.h>
#include <delays.h>
void PSX_DIG_main (void)
{
unsigned char holder;
PSX_Init_Pins();
SSPBUF=0xFF;
PSX_OPENSPI;
mLED_1_Off();
mLED_2_Off();
while(1)
{
PSX_CLOSESPI; //shutdown the SPI module
while(PSX_ATT); //sit and sping until the slave select line is low
PSX_OPENSPI; //start up the SPI module
if (holder == 0) //send out the last byte read unless is was 0
{ SSPBUF= 0x99; } //if it was zero, send 0x99 instead.
else
{SSPBUF = holder;}
while ((!SSPSTATbits.BF) && (!PSX_ATT)); // wait for a read cycle to complete
//was afraid there was a delay from the tiem the BF flag went high, and the SSPBUFF was updated from
//the SSPSR, so added a delay of four instructions before reading the SSPBUF.
_asm
nop
nop
nop
nop
_endasm
holder=SSPBUF; //stash the byte read, and repeat.
}
}//PSX_main()
void PSX_Init_Pins(void)
{
TRISAbits.TRISA5=1; //SS line - input
TRISCbits.TRISC7=0; //SDO - output
TRISBbits.TRISB1=1; //Clock - input
TRISBbits.TRISB0=1; //SDI - input
TRISCbits.TRISC6=0; //Line we're using for Ack
}
Last edited: