EmbeddedRelated.com
Forums

SPI, SSP on LPC2148 MCB2140 Keil Bug?

Started by highgatematem28 September 1, 2005
Hi All,

Has anyone set up the SPI or SSP on the LPC2148?

I cant get SPI0 to work at all, i.e. no SCK when I scope the dev board
(I have pull ups on SCK, MOSI0, MOI0 & SSEL0) and it is turned on in
the power reg.

void SPI_Init (void)
{
PINSEL0 = 0x00005500; // SPI Pins
IODIR0 = 0x00000400; // Chipselect
S0SPCCR = 0x000000FF; // bit timing
S0SPCR = 0x000000A0; // Master, Ints enabled

VICVectCntl0 = 0x0000002A;
VICVectAddr0 = (unsigned);
VICIntEnable = 0x00000400;
}

while(1)
{
SOSPDR = 0x5555; // write continuously to stimulate SCK
} So I thought I'll try the SSP instead.
Set that up with, no interrupts: -

void SPI1_Init (void)
{
PINSEL1 = 0x000002A8; // SPI1 pins
SSPCR0 = 0x00000007;
SSPCR1 = 0x00000002;
SSPCPSR = 0x00000002; // 30 MHz SCK
SSPCPSR = 0x00007530;
}

And the SPI1 SCK is there when I scope the hardware. Great!
But no.... try reading data from the SPI and it's not there. So I
start single stepping and find the data only stays in the SSPDR reg
for one assembler instruction and is then lost (Keil Bug?).

My read command is 0x9F, which should return 0x20.

So my function is:

void read_Device_Type(void)
{
IOCLR0 = 0x00000400; // Pull Chip Sel low
while (SSPSR & BSY); // wait for SPI Idle
SSPDR = 0x009F; // Write command (1)
while (!(SSPSR & TNF)); // Wait transmit
SSPDR = 0x0000; // Dummy write (2)
while (!(SSPSR & TNF)); // Wait transmit
input = SSPDR; // Data from device (3)
IOSET0 = 0x00000400; // Chip select high
}

Now, looking at the memory location of SSPDR I find that after (1)
SSPDR = 0xFF, then after (2) SSPDR = 0x20 (what I expect) but when I
read SSPDR at (3) it returns 0x00.

If I replace (2) with (3) I return 0x00 The disasembler reveals an STRH R1, [R0] instruction which shows the
correct return value but this is lost in the next LDR instruction.

Have scoped the data in and data out pins and I can see the correct
data on both.

Hope that gives you enough to understand, I spent all day on this....

Thanks,

Malcom


An Engineer's Guide to the LPC2100 Series

Hello Malcom,

Apart from the fact that the SSP supports several different serial
interfaces compared to the SPI0 (SPI/SSI/Microwire vs SPI only), the
key difference between the SSP and the SPI0 is the buffered
transmission: there is a 8 frame deep FIFO for transmitting and a 8
frame deep FIFO for receiving data. While sending data via SPI
master configured SSP seems pretty similar to SPI0 master operation
(simple write into the SSPDR), receiving data is a bit different.

Knowing that in any SPI mode for every single transmitted frame of
data one frame of data is received, you expect that after 0x9F is
sent, one byte is received. After sending 0x00, the second byte will
be sitting in the SSP Rx FIFO (the one you seem to be interested in).

Having said this, you would have to perform one dummy read from the
SSP Rx FIFO before you would actually access the desired data.

Also, keep in mind that with single stepping thru your code, you
have unintentionally performed several reads from the SSP Rx FIFO.
Additionally, you have not described the way you have declared
your "input" variable: was it "unsigned char input;" or "volatile
unsigned char input"? Declaring any variable that will be dealing
with a LPC2000 register(s) as a "volatile" works well for us when
testing hw/sw in Keil's uVision3 environment.

Recently we have tested LPC2148's SSP interface using a SPI Flash
memory PMC25LV512. Here is the code for reading SPI memory's ID.
This particular communication requires master to send a
command "0xAB" followed by 3 dummy bytes. At the end, three dummy
MOSI transmissions shift out Manufacturer and Device IDs.

void main (void) {
volatile unsigned char RAM_data; //temp variable
volatile unsigned char flash_re[16];
signed long int i;

//pin selection: P0.19(MOSI),P0.18(MISO),P0.17(SCK),P0.16(SSout)
PINSEL1 = 0x000000A8;
IODIR0 = 0x00010000;
IOSET0 = 0x00010000; //set SSout=1
//SSP initialization
SSPCR0 = 0x01C7; //8 bit SPI with CPHA=1,CPOL=1,SCR=1
SSPCR1 = 0x00; //SSP master (off) in normal mode
SSPCPSR = 0x02; //SPI clock
SSPCR1 = 0x02; //enable SSP master in normal mode
RAM_data = SSPDR; //read 8 bytes (clear SSP Rx FIFO)
RAM_data = SSPDR;
RAM_data = SSPDR;
RAM_data = SSPDR;
RAM_data = SSPDR;
RAM_data = SSPDR;
RAM_data = SSPDR;
RAM_data = SSPDR;

while(1){
//RDID command
IOCLR0 = 0x00010000; //select SPI Flash
SSPDR = 0xAB; //send command 0xAB...
SSPDR = 0x00; //send dummy byte 1
SSPDR = 0x00; //send dummy byte 2
SSPDR = 0x00; //send dummy byte 3
SSPDR = 0x00; //send dummy byte 4 (Rx man.id ID1)
SSPDR = 0x00; //send dummy byte 5 (Rx dev.id ID)
SSPDR = 0x00; //send dummy byte 6 (Rx man.id ID2)
while((SSPSR & 0x10)==0x10); //wait for the idle micro
for (i=0;i<=6;i++) //read 7 bytes from FIFO
flash_re[i]=SSPDR;
IOSET0 = 0x00010000; //deselect SPI Flash
}
}

In this example flash_re[4]=0x9D, flash_re[5]=0x7B, and flash_re[6]
=0x7F, as it is specified in the memory's documentation.

Regards,

Philips Apps Team

--- In lpc2000@lpc2..., "highgatematem28" <medwar19@h...>
wrote:
> Hi All,
>
> Has anyone set up the SPI or SSP on the LPC2148?
>
> I cant get SPI0 to work at all, i.e. no SCK when I scope the dev
board
> (I have pull ups on SCK, MOSI0, MOI0 & SSEL0) and it is turned on
in
> the power reg.
>
> void SPI_Init (void)
> {
> PINSEL0 = 0x00005500; // SPI Pins
> IODIR0 = 0x00000400; // Chipselect
> S0SPCCR = 0x000000FF; // bit timing
> S0SPCR = 0x000000A0; // Master, Ints enabled
>
> VICVectCntl0 = 0x0000002A;
> VICVectAddr0 = (unsigned);
> VICIntEnable = 0x00000400;
> }
>
> while(1)
> {
> SOSPDR = 0x5555; // write continuously to stimulate SCK
> } > So I thought I'll try the SSP instead.
> Set that up with, no interrupts: -
>
> void SPI1_Init (void)
> {
> PINSEL1 = 0x000002A8; // SPI1 pins
> SSPCR0 = 0x00000007;
> SSPCR1 = 0x00000002;
> SSPCPSR = 0x00000002; // 30 MHz SCK
> SSPCPSR = 0x00007530;
> }
>
> And the SPI1 SCK is there when I scope the hardware. Great!
> But no.... try reading data from the SPI and it's not there. So I
> start single stepping and find the data only stays in the SSPDR
reg
> for one assembler instruction and is then lost (Keil Bug?).
>
> My read command is 0x9F, which should return 0x20.
>
> So my function is:
>
> void read_Device_Type(void)
> {
> IOCLR0 = 0x00000400; // Pull Chip Sel low
> while (SSPSR & BSY); // wait for SPI Idle
> SSPDR = 0x009F; // Write command (1)
> while (!(SSPSR & TNF)); // Wait transmit
> SSPDR = 0x0000; // Dummy write (2)
> while (!(SSPSR & TNF)); // Wait transmit
> input = SSPDR; // Data from device (3)
> IOSET0 = 0x00000400; // Chip select high
> }
>
> Now, looking at the memory location of SSPDR I find that after (1)
> SSPDR = 0xFF, then after (2) SSPDR = 0x20 (what I expect) but when
I
> read SSPDR at (3) it returns 0x00.
>
> If I replace (2) with (3) I return 0x00 > The disasembler reveals an STRH R1, [R0] instruction which shows
the
> correct return value but this is lost in the next LDR instruction.
>
> Have scoped the data in and data out pins and I can see the
correct
> data on both.
>
> Hope that gives you enough to understand, I spent all day on
this....
>
> Thanks,
>
> Malcom