CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

SPI communication

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
rob norris
Guest







SPI communication
PostPosted: Wed Sep 29, 2004 1:06 pm     Reply with quote

Hello. I'm in a project where we are trying to make a PIC18F452 talk to a LCD controller chip via an SPI bus. For the last few days i've been getting nothing but random values back from the chip with the SPI_READ() command.

To test out the SPI bus, I disconnected the circuit and am now using two PIC microcontrollers to try to talk to each other, just to verify my SPI communication is working correctly. It turns out I'm having problems with this too.

The test I made is this: the master sends out either 01010101 or 10101010 across the bus. The slave then checks what it has recieved. If it has recieved the first byte i mentioned, it returns 11110000. If it has recieved the second byte I mentioned, it returns 00001111. The problem is, my master pic is reading back 01010101 and 10101010, which are the commands that it sent in the first place! I'm not sure how this is possible but it shows that I am not using the SPI bus correctly. I have the data-in and data-out pins on the pics crossed over and the master generating the clock (sclk) for the slave PIC.

Heres relevant code snipped from the master and slave code:

MASTER:

setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
while ( TRUE ){
SPI_WRITE(0b01010101);
xval = SPI_READ();
SPI_WRITE(0b10101010);
yval = SPI_READ();
printf("data: %U, %U\n\r", xval, yval);
delay_ms(200);
}

SLAVE:
setup_spi(SPI_SLAVE);
while(TRUE){
incomingCommand = SPI_READ();

if (incomingCommand = 0b10101010){
SPI_WRITE(0b11110000);
}

if (incomingCommand = 0b01010101){
SPI_WRITE(0b00001111);
}
}

Can anyone find anything wrong with what I am doing? Any help would be tremendously appreciated.. If I can figure out what the problem I'm having between the two PICS, i can probably figure out why the communication to the LCD controller is misbehaving. Thanks!!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Sep 29, 2004 1:14 pm     Reply with quote

Quote:

If I can figure out what the problem I'm having between the two PICS,
I can probably figure out why the communication to the LCD controller
is misbehaving.

I don't think that's a good approach. It's adding an entire new problem.
It's a new project, in fact.

I would study the LCD data sheet, and carefully setup the SPI timing
on the PIC so that it matches the LCD data sheet's requirements.
I would verify this timing with an oscilloscope or a logic analyzer.

What is the manufacturer and part number of your LCD ?
kloppy



Joined: 28 Jul 2004
Posts: 32

View user's profile Send private message

PostPosted: Wed Sep 29, 2004 2:30 pm     Reply with quote

what kind of lcd controller do you use?

i also used an lcd controller with spi and you need to consider a lot of things...
Ttelmah
Guest







PostPosted: Wed Sep 29, 2004 2:42 pm     Reply with quote

The key' is to remember that SPI talks in both directions _at once_ The byte received from the SPI, when the 'master' sends the first character, is whatever was sitting in the transmit register of the 'slave'. If you want to talk to a slave, and get a reply, you have to send a byte, wait long enough for the slave to have loaded the register, and then clock out another transmission, and then look at the received character. If the response is itself handled by another processor, it can be suprising how long the turnround time needs to be.
So in the case given, talking to a second PIC, this will receive the character, and interrupt at the end of the character. The interrupt latency can be very long (perhaps 30 instructions on a 16 chip, and as much as fifty instructions on a 18chip). Then the slave has to read the character, decide which reply to send, and load this into the output register, which takes perhaps another five instruction times. Only at this point, is the 'reply' ready to retrieve. Given that clocking the character itself, will take perhaps another 8 instruction times (depending on the clock rate selcted for the SPI), the reply will not be available till as much as 70 instruction times after first clocking the data out.
Where SPI is good, is on subsequent transfers. Assuming you send something like a command byte to trigger a particular transfer, you can then send the rest of the bytes at high speed (assuming the slave stays inside the interrupt handler), and accept a transfer back at the same time. For simple 'command/reply' transfers, I2C, is simpler, and nearly as fast.
The supplied CCS routines, are themselves 'irritating', when dealing with the SPI. I use a set of macros instead, which allow lower level access to the seperate parts:
Code:

#DEFINE       READ_SSP()   (SSPBUF)
#DEFINE   WAIT_FOR_SSP()   while((SSPSTAT & 1)==0)
#DEFINE   WRITE_SSP(x)   SSPBUF=(x)
#DEFINE   CLEAR_WCOL()   SSPCON=SSPCON & 0x3F

These assume you have allready defined the SSP registers, and then allow you to code like:
Code:

/* Launch - Used by both send and receive code to 'launch' communications */
void ssp_launch(int mode)
{
  int loop;
  while (true)
  {
    /* I loop till the slave responds to the header with a correct reply */
    /* This triggers the SPI transmission */
    WRITE_SSP(0xAA);
    WAIT_FOR_SSP();
    loop=READ_SSP(); //Garbage
    delay_cycles(80);
    /* This ensures the slave has time to enter the interrupt service routine */
    WRITE_SSP(mode);
    /* At this point the slave should have responded with '55' */
    WAIT_FOR_SSP();
    /* Since I clocked the write, the character should be waiting for me */
    /* I delay in this routine before actually reading, to allow the other end to get ready  for the next transfer */
    if (READ_SSP()==0x55) break;
  }
  delay_cycles(10);
}


I then transfer a complete block, to a memory buffer.
This approaches gives good performance that the PIC SPI (the hardware is fairly limited on the slave, where extra buffering, and 'identity' chcking hardware is commonly found on chips that are designed to handle the interface at higher speed.

Best Wishes
Charlie U



Joined: 09 Sep 2003
Posts: 183
Location: Somewhere under water in the Great Lakes

View user's profile Send private message

PostPosted: Wed Sep 29, 2004 6:27 pm     Reply with quote

You folks will probably all groan when you see me reply to an SPI question again, but I thought that I'd at least lob this over the wall again.

Here is the body of an email that I sent to CCS in Feb. 2002. I sent it again this past summer and they added buttons in the project wizard for the spi clock bits, but they got it wrong again. Sad I have filed another bug report with the following again to try to have them change the buttons to reflect the SPI modes NOT the pic clock bits.

Here's the email:
Quote:
I added some updates to an old project and suddenly the values returned from an external spi ADC were half what they had been!?!? The updates where purely cosmetic, such as display refinements. After investigating this problem over a couple of days, I have come to the conclusion that, using the standard #defines, the SPI is being set up incorrectly in the latest versions of the compiler.

The ADC works in either spi modes 0,0 or 1,1. In either case, the data on SDO is sampled by the slave on the rising edge of SCK. My F877 was setting the data on SDO simultaneously with the rising edge of SCK, which violated the setup requirement, when I used either SPI_L_TO_H or SPI_H_TO_L. Thus the slave was missing the start bit on SDO and delaying the start one clock and subsequently delaying the return data by one clock on SDI and thus the divide by 2 (>>1).

A little background:

If I'm not mistakcen, the SPI modes come from the SPI clock control bits on the Motorola 8 bit micros, such as the 68HC05 series, CPOL and CPHA.

(CPOL,CPHA)
0,0 is clock idle low and sample on the rising edge.
0,1 is clock idle low and sample on the falling edge.
1,0 is clock idle high and sample on the falling edge.
1,1 is clock idle high and sample on the rising edge.
(from Motorola AN991/D)

In the PIC F877 series (and others, all with MSSP?), CKP = CPOL and CKE = !CPHA. That is, the sense of the PIC CKE is inverted from the Motorola clock phase bit, CPHA. So, for

SPI 0,0 CKP = 0 and CKE = 1,
SPI 0,1 CKP = 0 and CKE = 0,
SPI 1,0 CKP = 1 and CKE = 1,
SPI 1,1 CKP = 1 and CKE = 0.

Now on to the problem at hand. I no longer have 2.734 of the CCS C installed, so I only have a sample of SPI_H_TO_L from the old days, but CKP was 1 and CKE was 0, which corresponds to SPI mode 1,1. That worked. If I compile the same code with 3.073, then CKP = 1 and CKE = 1, which is SPI mode 1,0, which doesn't work. Now, if I change the setup to SPI_L_TO_H then CKP = 0 and CKE = 0, which is SPI mode 0,1, and this doesn't work either.

Next I tried simply using a hex value for the setup rather than the defined values, such as:

setup_spi(SPI_MASTER|0x0000|SPI_CLK_DIV_4|SPI_SS_DISABLED);

This yielded the following:
0x4000 resulted in CKP = 0 and CKE = 1 or SPI mode 0,0.
0x0000 resulted in CKP = 0 and CKE = 0 or SPI mode 0,1.
0x0010 resulted in CKP = 1 and CKE = 1 or SPI mode 1,0.
0x4010 resulted in CKP = 1 and CKE = 0 or SPI mode 1,1.

This makes no logical sense to me, but it worked. Using 0x4010 the SPI operated in mode 1,1. There must be some routine in the compiler that configures the bits in some pattern.


I have created my own little include file with the above hex values and defined them as the SPI modes like:

#define SPI_mode_00 0x4000

I then use these in the spi setup functions and have had no trouble even with 18F452 parts.
Guest








PostPosted: Thu Sep 30, 2004 5:14 am     Reply with quote

Sorry. I should have included more information in the original post. The controller I am trying to connect to the PIC via the SPI bus is an LCD touch screen controller, not an LCD driver. Should have clarified that. The chip im using is the MXB7843 made by maxim:

[http://www.maxim-ic.com/quick_view2.cfm?qv_pk=3401]

The way this touch screen controller is supposed to work is you send it a command byte to request the X or Y position of the position being touched on the screen, and then the touch screen should process the command and return the appropriate value.

The touch screen controller requests a clock thats at least 500kHz and at most 2Mhz.. I played around with the DIV, and using "setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);" appears to give me around 1.1Mhz (says the oscilliscope), which appears to be a good value.

One thing which I'm not sure how to do is:

The manuel for the controller says "CPOL and CPHA = 0".. how do I set these values in CCS C? I read that they mean polarity and phase, but I'm not positive what they are or how to configure these settings.

Any advise would be greatly appreciated.
rob norris
Guest







PostPosted: Thu Sep 30, 2004 5:15 am     Reply with quote

that last message was posted my me, the thread started. Forgot to add my name up there.
Trampas



Joined: 04 Sep 2004
Posts: 89
Location: NC

View user's profile Send private message MSN Messenger

PostPosted: Thu Sep 30, 2004 7:05 am     Reply with quote

Personally when I start interfacing with a new device like an LCD I will often pull out my bit-bang SPI code. This allows me to operate the device really slow while watching the scope/LEDs to make sure the interface is working per the device's spec.

Once I get the device all working using the bit-bang interface I know that the PCB is correct and the device is connected correct. Then I can migrate the bit bang to the hardware SPI/I2C, etc.

This also has saved my butt more than once. For example I have upgraded the compiler and my SPI device stopped working. Now I had to determine if the problem was compiler, or the device I was working on. Thus by enabling the bit bang interface, I knew problem was compiler.

I know it sounds like a lot of work to make bit bang when there is hardware on the chip, but trust me it will save you time.

Trampas
rob norris
Guest







PostPosted: Thu Sep 30, 2004 7:09 am     Reply with quote

I figured out how to set CPOL and CPHA from Charlies reply. Both are set to 0 now by changing the SSPSTAT and SSPCON1 registers. I'm still having the same problem though, in getting values back from the touch screen controller... The touch screen controller is reading back 51,58 for the x,y coordinates now.. and give these values in all situations (whether your touching the screen anywhere or not)..

Does anyone have any further suggestions? It appears the timing and setup of the ssp bus is correct (to me)...

:(
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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 vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group