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 support@ccsinfo.com

spi headache

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



Joined: 23 Feb 2007
Posts: 55

View user's profile Send private message

spi headache
PostPosted: Fri Oct 12, 2007 6:12 am     Reply with quote

Hello,

I'm puzzling over a simple problem. I have two PIC18F4025 with an SPI link (SDI <-> SDO and SCK). I use spi_read / spi_write function to exchange data. The spi is working: the slave receives single bytes transmitted by the master.

Now I need to implement the following protocol:

Master <> Slave
*
byteM1 byteS1
byteM2 byteS2
byteM3 byteS3
byteM4 byteS4

In other words, the master send a '*' to synchronize the slave, then it sends its own four bytes while the slave answers with other four bytes.

This is the code for the slave:

Code:

typedef struct {
   int8   value;
   int16   range[2];
} pages;

pages page[4];

#int_SSP
void  SSP_isr(void) {
   char   rcv;

   if (rcvIndex == 255) rcv = spi_read();
   if ((rcv == '*' && rcvIndex == 255) || rcvIndex != 255) {
      rcvIndex++;
      rcvData[rcvIndex] = spi_read(page[rcvIndex]);
   }
   if (rcvIndex == 4) {
      rcvIndex = 255;
      dataReady = TRUE;
   }
}


In the main loop I check for dataReady in order to do something.


And this is for the master:

Code:

int8      brkProf[4];
typedef struct {
   int8   status;
   int8   value;
} brakes;

brakes brake[2];
.
.
.
for (;;) {
        spi_write('*');
   brkProf[0] = spi_read(brake[0].status);
   brkProf[1] = spi_read(brake[0].value);
   brkProf[2] = spi_read(brake[1].status);
   brkProf[3] = spi_read(brake[1].value);
        delay_ms(500);
}



The oscilloscope shows me some activity on the pins but the slave resets over and over....

What am I missing?

Thx,
Marco / iw2nzm
Ttelmah
Guest







PostPosted: Fri Oct 12, 2007 7:17 am     Reply with quote

Multiple things.
You only want one spi_read in the slave interrupt. The interrupt occurs, because _one_ byte is waiting. By reading two, you hold the slave inside the interrupt till the second byte arrives. However the logic then goes faulty. You cannot use spi_read(val), to write a value out the spi port on the slave. This form of the instruction, is for where a _master_ wants to clock out one byte, by reading another. On the slave, just use the spi_write instruction to put the data into the output buffer, _ready for the next master operation to transfer it_. In fact you need to always work one byte 'ahead', so what you need to do, is to load the first output byte, _when you receive the '*'_, and then advance for each character.
You are also trying to read and write a structure, when you need to access
an element... You dont show the declaration for the receive array, but assuming this is only a byte array.
So:
Code:

#int_SSP
void  SSP_isr(void) {
   char   rcv;

   rcv = spi_read(); //The character must be read.
   
   if ((rcv == '*' && rcvIndex == 255)
      spi_write(page[0].value);
      //output the first character, _ready_ for the next transfer
      rcvIndex=0;
   }
   else {
      rcvData[rcvIndex]=rcv;
      rcvIndex++;
      spi_write(page[rcvIndex].value);
      //write one character ahead of the receive
      if (rcvIndex == 4) {
      rcvIndex = 255;
      dataReady = TRUE;
   }
}

Now, you also don't give the clock rate being used, but you need to pause after sending a byte, long enough for the slave to have entered the interrupt, and got the next byte ready to send back. Typically perhaps 60 or more instruction times between the writes.

Best Wishes
iw2nzm



Joined: 23 Feb 2007
Posts: 55

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 8:40 am     Reply with quote

Thank for your complete answer Ttelmah. I completely misunderstood the spi behavior and the manual explanation too.

Despite your suggestion the slave continues to reset itself.

Let's see what I did:

Master:

Code:

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16 | SPI_SS_DISABLED);

.
.
.

spi_write('*');
delay_us(50);
brkProf[0] = spi_read(brake[0].status);
delay_us(50);
brkProf[1] = spi_read(brake[0].value);
delay_us(50);
brkProf[2] = spi_read(brake[1].status);
delay_us(50);
brkProf[3] = spi_read(brake[1].value);


The pause between transmission is a very long time, but I want to be sure there is no problem related to this.

Slave:

Code:

int1   dataReady = FALSE;
int8   rcvData[4];
int8   rcvIndex = 255;

setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_16 | SPI_SS_DISABLED);

.
.
.

#int_SSP
void  SSP_isr(void) {
   char   rcv;

   rcv = spi_read();
   
   if (rcv == '*' && rcvIndex == 255) {
      spi_write(page[0].value);
      rcvIndex = 0;
   } else {
      rcvData[rcvIndex++] = rcv;
      if (rcvIndex == 4) {
         rcvIndex = 255;
         dataReady = TRUE;
      } else {
         spi_write(page[rcvIndex].value);
      }
   }
}


Before I forgotten to show the rcvData declaration: as you said it's a byte array. I changed the last part of the isr because after writing the four values I still have to receive one byte. But I have no more data to transmit.

Please, might you suggest me how to debug and fix the problem?

Thanks again
Marco / iw2nzm
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Oct 12, 2007 9:13 am     Reply with quote

Only something I noticed at quick glance
Code:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16 | SPI_SS_DISABLED);
SPI_SS_DISABLED is only allowed for the slave. Check the header file for your processor and you will see the defined value conflicts with the SPI_CLK_DIV_xx definitions.

A PIC resetting itself is rare. Make sure you have:
- disabled the watchdog.
- a stable power supply.
- check for stack overflow (from top of the *.lst file).
- brown out settings that make sense (if applicable for your chip).
iw2nzm



Joined: 23 Feb 2007
Posts: 55

View user's profile Send private message

PostPosted: Sun Oct 14, 2007 3:41 am     Reply with quote

UPDATE

So I solved the reset problem. Don't ask me how I did. I just cut & paste the same code in the same place and the reset gone away. I guess the CCS IDE is quite buggy, sometimes it crashes or hangs-up while I'm writing. I'm going to use an external editor such as the Programmer's notepad. Maybe it was better I didn't buy the IDE but just the compiler.

However, I partially solved the SPI issue. Now I can successfully transmit data from master to slave. It stops working (see later) when I try to send data back from slave to master.

A bit of code:

Master

Code:

#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1  (SPI_L_TO_H)
#define SPI_MODE_1_0  (SPI_H_TO_L)
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

setup_spi(SPI_MASTER | SPI_MODE_1_1 | SPI_CLK_DIV_64);

for (;;) {
        delay_ms(250);
        spi_write('*');
   delay_us(100);
   brkProf[BRKSRT] =   spi_read(brake[0].status);
   delay_us(100);
   brkProf[BRKACQ] =   spi_read(brake[0].value++);
   delay_us(100);
   brkProf[BRKSTP] =   spi_read(brake[1].status);
   delay_us(100);
   brkProf[BRKVAL] =   spi_read(brake[1].value++);
}


Please note all variables involved are declared as int8.

Slave:

Code:

#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1  (SPI_L_TO_H)
#define SPI_MODE_1_0  (SPI_H_TO_L)
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

setup_spi(SPI_SLAVE | SPI_MODE_1_1 | SPI_SS_DISABLED);

#int_SSP
void  SSP_isr(void) {
   char   rcv;

   rcv = spi_read();
   if (rcv == '*' && rcvIndex == 255) {
      //spi_write(10);   <--------------------- this will cause weird data
      rcvIndex = 0;
   } else {
      rcvData[rcvIndex++] = rcv;
      if (rcvIndex == 4) {
         rcvIndex = 255;
         dataReady = TRUE;
      } //else {
         //spi_write(page[rcvIndex].value);   //(I try to send only 1 byte now)
      //}
   }
}



If the slave send nothing all works fine. If I enable the line spi_write(10); I note strange behavior such as bit shifting in read data or loss of synchronization (byte shifting).

I'm pretty sure I mess something in the spi configuration. Since yesterday evening I'm reading a tons of post in this forum about the topic. But I'm still not able to fix the problem.


Thanks to all
Marco / iw2nzm
Ttelmah
Guest







PostPosted: Sun Oct 14, 2007 4:06 am     Reply with quote

Try just putting the byte into the SPi register.
Unfortunatly, the CCS SPI code, is not really written to handle slave transmissions. If I remember correctly, it actually waits for the transfer to complete, before returning. This is not what is wanted at all, when dealing with an interrupt driven slave. :-(
Use:
Code:

//For PIC18 chips. Will need to change for others
#byte   SSPBUF = 0xFC9
#byte   SSPCON = 0xFC6
#byte   SSPSTAT = 0xFC7
#bit BF = SSPSTAT.0

/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for interrupt driven slave operations... */
#DEFINE READ_SSP()   (SSPBUF)
#DEFINE   WAIT_FOR_SSP()   while(!BF)
#DEFINE   WRITE_SSP(x)   SSPBUF=(x)
#DEFINE   CLEAR_WCOL()   SSPCON=SSPCON & 0x3F

Just use the 'READ_SSP' function, to get the byte in the interrupt handler, and the 'WRITE_SSP' function, to write the returned data.
I was slightly 'hoping' that the latter versions of the compiler, might have improved this behaviour, but had to 'go DIY' in the past.

Best Wishes
iw2nzm



Joined: 23 Feb 2007
Posts: 55

View user's profile Send private message

PostPosted: Sun Oct 14, 2007 4:28 am     Reply with quote

Razz I want to say you a BIG thank you. Razz

It works like a charm. The problem was the bad CCS code.
Furthermore, I've just killed the CCS IDE and I'm using the PN as editor.

Thanks again
Marco / iw2nzm
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