Logomatic V2 using SPI1

Hi All,

I’m looking for your assistance to get the SSP SPI1 port on the Logomatic V2 operational. While I am specifically looking to communicate with the LSI3LV02DQ accelerometer module, i’m thinking that this should be relatively generic in its setup.

I have spent considerable time searching this forum (and others related to LPC2000) and reviewing the NXP manual without much success.

So here is what i have so far.

My SSP SPI1 init code is:

//Initialise I/O Ports and Peripherals

//Outputs

IODIR0 = SCLK0 | MOSI0 | CS_SD | SCLK1 | MOSI1 | CS_ACCEL | LED_RED | LED_GREEN;

//Inputs

IODIR0 &= ~(MISO0 | MISO1 | BATT_MEAS);

//Make sure peripheral devices are not selected

UnselectAccelerometer();

//Initialize the SPI bus

SPI0_Init(); // Select pin functions for SPI0 signals.

S0SPCCR = 64; // SCK = 1 MHz (60MHz / 64 ~= 1Mhz)

S0SPCR = 0x20; // Master, no interrupt enable, 8 bits

SPI1_Init(); // Select pin functions for SPI1 signals.

SSPCR1 = 0x00; // Disable SSP SPI1

// SSPCPSR clock prescale register, master mode, minimum divisor is 0x02

// SCK1 = PCLK / (CPSDVSR * [SCR+1])

SSPCPSR = 60; // SCK = 1 MHz (60MHz / 60 ~= 1Mhz)

SSPCR0 = 0x07; // CPHA=0, CPOL=0, FRF=01(SPI mode), DSS=0111(8 bits)

// SSPCR1 = 0x02; // Master, SSP enable

SSPIMSC = 0x00; // no interuupt enable

SSPCR1 |= (1 << 1); // SSP Enable

for(i = 0;i < 8;i++)

{

Dummy = SSPDR; // clear the RxFIFO

}

As best as i can interpret chapter 13 of the NXP manual, this appears to be okay.

Now, my SPI1.h code is

#define BSY (1<<4)

void SPI1_Init(void);

void SPI1_send(char c);

char SPI1_recv(void);

char SPI1_send_recv(char c);

and SPI1.c code is

#include “spi1.h”

#include “LPC214x.h”

#include <stdio.h>

void SPI1_Init(void){

//This function needs to go in bootup() of Main.c

PINSEL1 = (PINSEL1 & ~(3 << 2)) | (1 << 3); // Enable SCLK1 on P0.17

PINSEL1 = (PINSEL1 & ~(3 << 4)) | (1 << 5); // Enable MISO1 on P0.18

PINSEL1 = (PINSEL1 & ~(3 << 6)) | (1 << 7); // Enable MOSI1 on P0.19

}

void SPI1_send(char c){

while (!(SSPSR & 0x02));

SPI1_send_recv(c);

}

char SPI1_recv(void){

return SPI1_send_recv(0xff);

}

char SPI1_send_recv(char c){

int in;

SSPDR = c; // Place data to be sent into SPI data register

while(!(SSPSR & !BSY)); // Wait for transfer to complete

in = SSPDR&0xff; // Return the character placed in the SPI data register by the slave

return in;

}

As best as i have been able to confirm my application is stopping at the SPI1_send_recv(c) function.

For info i guess, i am using WINARM and programmers note pad for this project.

If you have a working example of code for the SPI1 port on the logomatic V2 OR can advise the correction to my code (above) i’d appreciate you help.

Thanks

Neil

Neil, here are a few things you might try to get your code working:

First, get rid of the SPI0 and SPI1 stuff (SCLK0, MOSI0, SCLK1, MOSI1, MISO0, and MISO1) when you set the IODIR0 register in this code:

//Initialise I/O Ports and Peripherals
//Outputs
IODIR0 = SCLK0 | MOSI0 | CS_SD | SCLK1 | MOSI1 | CS_ACCEL | LED_RED | LED_GREEN;
//Inputs
IODIR0 &= ~(MISO0 | MISO1 | BATT_MEAS);

These definitions are not needed and may actually be causing problems. Here is what the LPC214x Manual says:

The PINSEL1 register controls the functions of the pins as per the settings listed in

following tables. The direction control bit in the IO0DIR register is effective only when the

GPIO function is selected for a pin. For other functions direction is controlled

automatically.

Peripherals should be connected to the appropriate pins prior to being activated, and prior

to any related interrupt(s) being enabled. Activity of any enabled peripheral function that is

not mapped to a related pin should be considered undefined.

Once you set the SPI bits in the PINSEL1 register, the direction is taken care of automatically.

Second, get rid of the double negative here:

while(!(SSPSR & !BSY)); // Wait for transfer to complete

This is functionally correct, but there’s no point in negating something twice. Just do it like this:

while (SSPSR & BSY); // Wait for transfer to complete

Good work on this one though. You must have read the manual because the Philips code examples all have this one wrong. They are doing while!(SSPSR & BSY); which doesn’t actually wait for anything.

Finally, give this a try and let me know if it fixes your problem. The LPC214x manual isn’t very clear on this. It explicitly says you can redefine SSEL0 when you are using SPI0 in master mode, but it DOESN’T say anything about re-defining SSEL1. In fact, the behavior of the two ports is quite different. To start SCLK0 you just put data into S0SPDR and it starts the clock. However, with SPI1 it seems that the driving of SSEL1 low causes SCLK1 to start. From the manual:

If the SSP is enabled and there is valid data within the transmit FIFO, the start of

transmission is signified by the SSEL master signal being driven LOW. This causes slave

data to be enabled onto the MISO input line of the master. Master’s MOSI is enabled.

Basically, I think you need to enable SSEL1 from PINSEL1 by adding one more line of code to what you've got:
PINSEL1 = (PINSEL1 & ~(3 << 2)) | (1 << 3); // Enable SCLK1 on P0.17
PINSEL1 = (PINSEL1 & ~(3 << 4)) | (1 << 5); // Enable MISO1 on P0.18
PINSEL1 = (PINSEL1 & ~(3 << 6)) | (1 << 7); // Enable MOSI1 on P0.19
PINSEL1 = (PINSEL1 & ~(3 << 8)) | (1 << 9); // Enable SSEL1 on P0.20

Note, you can still use a different chip select line - just be sure to drive it low manually when you are selecting a peripheral.

Hope this solves your problem!

-Chris

Hi Chris,

Many thanks for your reply. I’ll work through this over the coming week and let you know how i get on.

Regards

Neil

Neil,

I did some checking over the weekend. I have an LPC2148 with a working SSP port talking to an OLED. I moved the chip select line from SSEL1 to a generic GPIO and then removed the PINSEL1 assignment. Everything still works fine, so I’m guessing my final suggestion to you isn’t going to make any difference. Sorry. :frowning:

I see you’re using the Logomatic V2 which has a UART0 programming header (JP1). If you don’t already have one, you could buy a Sparkfun LPC Serial Port Boot Loader Interface dongle. It has a switch on it for serial flash programming, but as long as the switch is flipped the other way, you can use it to send debug messages to your PC.

http://www.sparkfun.com/commerce/produc … cts_id=714

You just need a serial cable and a 6-pin female header.

http://www.sparkfun.com/commerce/produc … ucts_id=65

http://www.sparkfun.com/commerce/produc … cts_id=115

Solder the female header into the JP1 holes on your Logomatic PCB. Then you can plug and unplug the dongle at will. In your code, just use rprintf(“my debug message”) function calls to send text to HyperTerminal on your computer. Now, you can put a bunch of debug statements in your SPI1 functions to see where things are going wrong.

Hope this helps!

-Chris

Did you ever get anywhere with this?

I am trying to get an SCP1000 to work with the Logomatic but its not playing ball.

I have tracked the bug down to the while where it waits for the SSP status to be !busy.```
while (SSPSR & BSY);


It just hangs in that while infinitely.

Any clues as to why SSPSR is always reading busy?

If it helps, when I read and output SSPSR is always gives me 10010

There is quite a lot of SPI stuff in my LPC2000 Yahoo group files section. It’s mostly for accessing SD cards, but it should help.

Leon

I eventually got SPI1 and the SCP1000 to work on the Logomatic.

Biggest problem was probably the SSEL line wasn’t being setup and the CPOL was the wrong polarity. SCP1000 needs idle high…

I also took out all the SelectSCP() and UnselectSCP() code. When you use the SSEL pin it automatically gets pulled low (in this case) when the SSP clock starts.

Here is the SPI1 code I came to in case anyone comes across this thread:

SPI1.h

#ifndef SPI1_H
#define SPI1_H

	void SPI1_Init(void);
	void SPI1_send(char c);
	char SPI1_recv(void);
	char SPI1_send_recv(char c);
	
	int SPI1_transfer_pend(void);
	char SPI1_get_rx(void);
	void SPI1_send_noblock(char c);

#endif

SPI1.c

#include <stdio.h>
#include "LPC214x.h"
#include "main.h"
#include "spi1.h"

/* SSP (SPI1) pins (UM10120_1.pdf page 76)
   P0.17 SCK    PINSEL1 2 << 2
   P0.18 MISO   PINSEL1 2 << 4
   P0.19 MOSI   PINSEL1 2 << 6
   P0.20 SS     PINSEL1 2 << 8 
*/
#define PINSEL1_SCK  (2 << 2)
#define PINSEL1_MISO (2 << 4)
#define PINSEL1_MOSI (2 << 6)
#define PINSEL1_SSEL (2 << 8)

/* SSPCR0 settings */
#define SSP_DSS  0x07 << 0  /* data size            : 8 bits    */
#define SSP_FRF  0x00 << 4  /* frame format         : SPI       */
#define SSP_CPOL 0x01 << 6  /* clock polarity       : idle high */  //(Needs high for SCP1000)
#define SSP_CPHA 0x01 << 7  /* clock phase          : 1         */
#define SSP_SCR  0x0F << 8  /* serial clock rate    : 58.59kHz = PCLK / (CPSDVSR * [SCR+1]) = 15000000 / (16 * [15+1]) */ 

/* SSPCR1 settings */
#define SSP_LBM  0x00 << 0  /* loopback mode        : disabled */
#define SSP_SSE  0x00 << 1  /* SSP enable           : disabled */
#define SSP_MS   0x01 << 2  /* master slave mode    : slave    */
#define SSP_SOD  0x00 << 3  /* slave output disable : disabled */

#define CPSDVSR    16		//32

void SPI1_Init(void)
{
	/* setup pins for SSP (SCK, MISO, MOSI, SS) */
	PINSEL1 |= PINSEL1_SCK | PINSEL1_MISO | PINSEL1_MOSI | PINSEL1_SSEL;

	/* setup SSP  */
	SSPCR0 = SSP_DSS | SSP_FRF | SSP_CPOL | SSP_CPHA | SSP_SCR;
	SSPCPSR = CPSDVSR; /* Prescaler, UM10120_1.pdf page 167 */

    SSPCR1 = (1 << 1); /* Enable the module */

    int a;
    a = SSPDR; //GCC warning clear

    while( (SSPSR & (1<<1)) == 0 );
}

void SPI1_send(char c)
{
    SPI1_send_recv(c);
}

char SPI1_recv(void)
{
    return SPI1_send_recv(0xff);
}

char SPI1_send_recv(char c)
{
    int in;

    SSPDR = c;
	
	// Wait for transfer to complete
    while(SPI1_transfer_pend());

    in = SSPDR;//&0xff; not sure if this matters or not... works without out it, less is more :-)
    return in;
}

/* Returns 0 if no transfer pending
 * Bit 0 indicates tx not empty
 * Bit 1 indicates rx empty
 */
int SPI1_transfer_pend(void)
{
    int result = 0;
    if(((SSPSR & (1<<0)) == 0))/* if the Transmitter is full */
    {
        result += 1;
    }   
    if(((SSPSR & (1<<2)) == 0))/* or the receiver is empty */
    {
        result += 2;
    }
	
    return result;
}

char SPI1_get_rx(void)
{
    while((SSPSR & (1 << 2)) == 0);
    return (SSPDR&0xff);
}

void SPI1_send_noblock(char c)
{
    SSPDR = c;
}