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

Interrupt based SPI routine - PIC24F - Issue receiving data
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

Interrupt based SPI routine - PIC24F - Issue receiving data
PostPosted: Tue Jan 29, 2013 4:33 pm     Reply with quote

Hello,

Ive been working on a simple master slave connection between two chips, but have noticed that the slave chip rather than reading in new data returns the parameter in the SPI_READ function (as shown below).
I have verified the master-code by setting up a loop-back which seems to work fine, but cant seem to see why the slave is getting garbage values.

Also I noticed if the slave returns a value in SPI_READ via the parameter the interrupt stops processing at 6th byte which I cant explain. 13 bytes (size of my buffer) are clocked in (e.g. interrupt triggered but still no data) if there is no parameter

I double checked the wiring, master SDO goes to slave SDI and slave SDO goes to master SDI.

Before I waste days dissecting assembly code could anyone share some insight? Thanks in advance peoples

Using PCD 4.138
Masterchip: PIC24F16KA102
Slavechip: PIC24fj128GA010 (Explorer 16 Development Board)


Slave code:
Code:

// This interrupt driven SPI program forms part of the SignalGenerator module
// which receives 100bits from the Interpreter.
// Time packet sent, in exchange the current pulse tracking error is returned
#include <24fj128GA010.h>

#fuses NODEBUG      // Debug Mode. 1.11   NODEBUG   No Debug mode for ICD
#fuses HS,PR_PLL   // Crystal HS, 4xPLL -- FRC_PS : Internal OSC (8MHz) with postscaler (PS set automatically in #use delay)
#fuses NOIESO       // No 2-speed Start Up
#fuses NOJTAG       // No JTAG
#fuses NOPROTECT    // No Memory Protection
#fuses NOWDT        // No WatchDog Timer

#use delay(clock=32M, crystal=8M)
#use rs232(UART2, STREAM=serial_debug, baud=9600, bits=8)

#define buffers 2
#define bufferSize 13

int intrTriggered = 0;
int bufferPos = 0;
int bufferWrite = 1, bufferRead = 0;
int8 SPIreturnValue = 16; // SPI writes 8bit by default
BOOLEAN isrflag = FALSE;

union DataBuffer {
   int8 SPI[bufferSize];
   int1 signalData[8*bufferSize];
} IRIG[buffers]; // dual-buffer setup

int i;

#INT_SPI1 FAST // SPI 1 activity
void ReceiveDataSPI()
{
   IRIG[bufferWrite].SPI[bufferPos] = spi_read(intrTriggered); // fetch data

   bufferPos++; // move to next free slot
   
   if(bufferPos >= bufferSize) // if buffer is full...
   {
      bufferPos = 0; // reset buffer, jump to other buffer
      bufferRead = bufferWrite; // ... bufferRead is altered once all data is read (thus, not yet... done here only for testing purposes)
      bufferWrite = (++bufferWrite) % buffers; // two buffers exist, when one full jump to other

      isrflag = TRUE; // indicate data is ready
   }
   
   intrTriggered += 1;
}

#INT_SPI1E
void ErrorSPI()
{
   printf("\n\rError detected :(\n\r");
}

void main()
{   
   int lastVal = 0;

   setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64);   // initialise SPI-HW module for sender

   enable_interrupts(INT_SPI1 );      // Enable output compare interrupt
   enable_interrupts(INT_SPI1E );         
   enable_interrupts(INTR_GLOBAL);      // Enable tracking

   printf("Successful, waiting for input...\r\n");
   
   while(TRUE) {
      if(lastVal != intrTriggered) // detect if interrupt even triggered
      {
         printf("SPI activity: %u, buf: %u, val: %u\r\n",intrTriggered,bufferPos-1,IRIG[bufferWrite].SPI[bufferPos-1]);
         lastVal = intrTriggered;
      }
      
      if(isrflag) // print buffer when full, always transmitted as batch
      {
         printf("SPI Values: ");
         
         for(i=0; i<bufferSize; i++)
         {
            printf("(%d,%d) ",i, IRIG[bufferRead].SPI[i]); // print all data to PC
         }
         printf("\r\n");
         isrflag = FALSE;
      }
   }
}


Slave output:

Code:

Successful, waiting for input...
SPI activity: 1, buf: 0, val: 0
SPI activity: 2, buf: 1, val: 0
SPI activity: 3, buf: 2, val: 0
SPI activity: 4, buf: 3, val: 2
SPI activity: 5, buf: 4, val: 2
SPI activity: 6, buf: 5, val: 4


Master code:
Code:

// This code forms part of the Interpretor module
// It sends 13 bytes of data, represents an IRIG-packet
#include <24F16KA102.h>

#fuses NODEBUG      // Debug Mode. 1.11   NODEBUG   No Debug mode for ICD
#fuses FRC_PLL      // Crystal HS, 4xPLL -- FRC_PS : Internal OSC (8MHz) with postscaler (PS set automatically in #use delay)
#fuses NOIESO       // No 2-speed Start Up
#fuses NOPROTECT    // No Memory Protection
#fuses NOWDT        // No WatchDog Timer

#use delay(clock=32M, internal=8M)
#use rs232(UART2, STREAM=serial_debug, baud=9600, bits=8)

#define buffers 2
#define bufferSize 13

int outIndex = 0, outDataSize=64; // PR is set to every second (1M/2/256=1sec /2 comes from internal clock delay Fosc/2, only occurs when OSC is internal ) //15625;
int bufferPos;
int bufferWrite = 1, bufferRead = 0;
int8 SPIreturnValue = 0;
BOOLEAN isrflag = FALSE;


int8 SPIsampleData[bufferSize]={1,2,3,4,5,6,7,8,9,10,11,0xFF,13};
int i;

void main()
{   

   printf("Data Transfer via SPI\r\n");

   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64);   // initialise SPI-HW module for sender

   printf("Successful, ready to send...\r\n");
   
   delay_ms(100);
   
   
   printf("Sending values via SPI \r\n");
   for(i=0; i<bufferSize; i++)
   {
      printf("%u %u\r\n",i,SPIsampleData[i]);
   }
   

   printf("Sending values via SPI \r\n");
   
   for(i=0; i<bufferSize; i++)
   {
      SPIreturnValue = spi_read(SPIsampleData[i]);
      output_high(PIN_A2); // B5
      printf("%u %Lu\r\n",i,SPIreturnValue);
      delay_ms(100);
      output_low(PIN_A2);
   }
   
   printf("Done.\r\n");


   while(TRUE);
}
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Wed Jan 30, 2013 3:13 am     Reply with quote

Just to add, the fact that inserting a parameter into SPI_READ (slave) will essentially always return the value I gave to SPI_read (slave). Then it cuts off after the 6th byte, so I omitted the parameter and here is what I get:

Code:

Successful, waiting for input...
SPI activity: 1, buf: 0, val: 1
SPI activity: 2, buf: 1, val: 0
SPI activity: 3, buf: 2, val: 0
SPI activity: 4, buf: 3, val: 0
SPI activity: 5, buf: 4, val: 0
SPI activity: 6, buf: 5, val: 0
SPI activity: 7, buf: 6, val: 0
SPI activity: 8, buf: 7, val: 0
SPI activity: 9, buf: 8, val: 0
SPI activity: 10, buf: 9, val: 0
SPI activity: 11, buf: 10, val: 0
SPI activity: 12, buf: 11, val: 0
SPI activity: 13, buf: 65535, val: 0


However the received data is zero, supposedly because the compiler replaces an empty parameter with 0.

Kind regards
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Wed Jan 30, 2013 3:17 am     Reply with quote

Also,

I used these threads for reference

spi problem with pic24F
http://www.ccsinfo.com/forum/viewtopic.php?t=43029
(Using the same chip as well...)

H/W SPI on a pic24
https://www.ccsinfo.com/forum/viewtopic.php?t=38491&postdays=0&postorder=asc&start=30

Sample code of Interrupt based SPI Slave?
http://www.ccsinfo.com/forum/viewtopic.php?t=26888&start=1
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Thu Jan 31, 2013 12:14 pm     Reply with quote

Hmm, I cant seem to see any reason why the program is misbehaving. I checked the config and stat flags which look fine nor are any errors raised

Has anyone by any chance had any success getting HW interrupt triggered SPI working on a PIC24F compiler version PCD 4.138?

Help much appreciated Confused
Thanks,
John
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Thu Jan 31, 2013 7:18 pm     Reply with quote

One thing that could cause an issue is you are using printf in both an interrupt and the main, which means interrupts will be disabled when you go into the printf in the main. This could cause you to miss data if it comes while you are doing the printing.

I don't have time to go through it more than that at this point, but something to play with at least.
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 2:58 am     Reply with quote

Hi jeremiah, thanks for the suggestion. Im worried that Ive been starring at code for 4-5 days now that im missing obvious things... so thanks, I really appreciate any thoughts Smile

As for the printfs, I removed all of them but it didn't have an effect. As in it stops after 6 bytes again. I guess that wasnt critical because the master inserts a 100ms delay after each transfer just to keep things simple for the moment.

Thanks though
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 3:51 am     Reply with quote

Cut the code down to the bare minimum and its still exhibiting this behaviour. Oh my... if anybody has reference code working on PIC24F with interrupt I would extremely grateful Embarassed

Code:

#include <24fj128GA010.h>

#fuses NODEBUG      // Debug Mode. 1.11   NODEBUG   No Debug mode for ICD
#fuses HS,PR_PLL   // Crystal HS, 4xPLL -- FRC_PS : Internal OSC (8MHz) with postscaler (PS set automatically in #use delay)
#fuses NOIESO       // No 2-speed Start Up
#fuses NOJTAG       // No JTAG
#fuses NOPROTECT    // No Memory Protection
#fuses NOWDT        // No WatchDog Timer

#use delay(clock=32M, crystal=8M)
#use rs232(UART2, STREAM=serial_debug, baud=9600, bits=8)

int8 rcvVal, lastVal = 0, intrTriggered = 0;

#INT_SPI1  // SPI 1 data ready
void ReceiveDataSPI()
{
   rcvVal = spi_read(intrTriggered); // fetch data //IRIG[bufferWrite].SPI[bufferPos]
   intrTriggered += 1;
}

void main()
{   
   setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64);

   enable_interrupts(INT_SPI1 );      // Enable output compare interrupt         
   enable_interrupts(INTR_GLOBAL);      // Enable tracking

   while(TRUE) {
      if(lastVal != intrTriggered) // detect if interrupt even triggered
      {
         printf("SPI activity: %u, val: %u\r\n",intrTriggered,rcvVal);
         lastVal = intrTriggered;
      }
   }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 5:31 pm     Reply with quote

I don't have the PCD compiler so I'm reluctant to reply, but anyway:

1. Implement the Slave Select line from Master to Slave. See if that helps.

2. Also, as a comment, you have SS disabled in the Master. But that
parameter only applies to the Slave PIC. If you use it in the Master
code, it can have unexpected results.
Quote:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64); // initialise SPI-HW module for sender

For example in the 18F PICs, it can change the SPI clock divisor to
a different value. I don't know how it would affect a 24F.
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 7:17 pm     Reply with quote

PCM programmer wrote:
I don't have the PCD compiler so I'm reluctant to reply, but anyway:

1. Implement the Slave Select line from Master to Slave. See if that helps.

2. Also, as a comment, you have SS disabled in the Master. But that
parameter only applies to the Slave PIC. If you use it in the Master
code, it can have unexpected results.
Quote:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64); // initialise SPI-HW module for sender

For example in the 18F PICs, it can change the SPI clock divisor to
a different value. I don't know how it would affect a 24F.


Agreed.

On the master, the coder is required (usually) to implement the slave select line. This is usually because an SPI MASTER can have more than 1 slave.

On the slave, ABSOLUTELY enabled the nSS line. otherwise, the slave never gets enabled properly.

I can't recommend strongly enough that you search on the net, download and carefully read about the SPI protocol. (Your test code hints that you have not yet - else you would not have left out something as crucial as the slave select line.)

I have PCD, but I don't have a setup that would allow me testing anything more than the compile part.

Cheers,

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 7:19 pm     Reply with quote

Additionally, in your code:

Code:
#INT_SPI1  // SPI 1 data ready
void ReceiveDataSPI()
{
   rcvVal = spi_read(intrTriggered); // fetch data //IRIG[bufferWrite].SPI[bufferPos]
   intrTriggered += 1;
}


Why are you getting more than one byte/word of SPI data with intrTriggered?

You should only get as many results as are in the FIFO (if you have it enabled on this PIC and it supports it - a lot of the PIC24's have a multi-register FIFO and your code isn't the way you do it. )

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
jeremiah



Joined: 20 Jul 2010
Posts: 1346

View user's profile Send private message

PostPosted: Fri Feb 01, 2013 7:32 pm     Reply with quote

PCM programmer wrote:

2. Also, as a comment, you have SS disabled in the Master. But that
parameter only applies to the Slave PIC. If you use it in the Master
code, it can have unexpected results.
Quote:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_SS_DISABLED | SPI_CLK_DIV_64); // initialise SPI-HW module for sender

For example in the 18F PICs, it can change the SPI clock divisor to
a different value. I don't know how it would affect a 24F.


Ironically, a few days ago, I ran into the exact opposite problem (dsPIC33F on the most recent compiler). I was having trouble with an I/O line not working. I noticed it was on the SS line for SPI1, so I added the SS disable option even though I was running master mode and not slave mode. It fixed my I/O problem. I haven't taken the time to figure out why, but found it odd since, as a rule of thumb, I too avoid specifying that parameter in master mode.
john.ma



Joined: 19 Nov 2012
Posts: 23

View user's profile Send private message

PostPosted: Sat Feb 02, 2013 12:20 pm     Reply with quote

Hi people,

Thanks for the time and thought everyone.

I took PCM programmers advice regarding the SS_DISABLE flag and inserted a proper chip select line. Unfortunately had no effect on the general issue, aka still no reliable output.
Note: the reason I initially used the flag is because its a p2p connection, there is only 1 slave and 1 master.
PCD manual states: SPI_SS_DISABLED will turn off the slave select pin so the slave module receives any transmission on the bus.
... but thanks for the point, Ill remember for the future Smile

I also got rid of the SPI_CLK_DIV_XX on the slave SPI_setup as that is generated by the master and not the slave... had no effect.

I tried different transfer modes... no effect

Rewrote the code to use SPI2, rather than SPI1... no effect

Im starting to believe its got something to do the SPI_read function, namely how it takes a parameter and inserts it onto the SPIxTXB.

@bkamen: As for
Code:
rcvVal = spi_read(intrTriggered);
, that has nothing to do with enhanced buffer modes merely a value which is returned as part of the SPI exchange as explained by the manual:
Quote:

in_data = spi_read(out_data);
Returns:
An 8 bit int
Function:
Return a value read by the SPI. If a value is passed to spi_read() the data will be clocked out and the data received will be returned. If no data is ready, spi_read() will wait for the data if A SLAVE or return the last DATA clocked in from spi_write.


Any other ideas? :(
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Sat Feb 02, 2013 12:54 pm     Reply with quote

but even in a point to point connection, nCS has features usually forgotten like:

* framing in a stream where a slave may come up in the middle of a transmission.

* resetting the receiver's state machine on an error with multi-byte transfers.


So don't discount it.

Do you have a scope to watch the transmission?

Also, don't forget that while the master is still transmitting a byte/word, because the SPI clock is must slower than the CPU clock, if you don't monitor the SPI transmit buffer empty flag, you can release the nSS line too early and truncate a transfer in progress.
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Sat Feb 02, 2013 12:59 pm     Reply with quote

john.ma wrote:

@bkamen: As for
Code:
rcvVal = spi_read(intrTriggered);
, that has nothing to do with enhanced buffer modes merely a value which is returned as part of the SPI exchange as explained by the manual:
Quote:

in_data = spi_read(out_data);
Returns:
An 8 bit int
Function:
Return a value read by the SPI. If a value is passed to spi_read() the data will be clocked out and the data received will be returned. If no data is ready, spi_read() will wait for the data if A SLAVE or return the last DATA clocked in from spi_write.




yea.. I re-read that realizing you were just sending back the number of bytes read.

You should hook a scope up to the lines it this point. You'll save a LOT of time watching what's going on.

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Sat Feb 02, 2013 3:02 pm     Reply with quote

I'd separate things.
Try:
Code:

RcvVal=spi_read();
spi_write(IntrTriggered++);


If you read the manual entry for spi_read, it says that if you pass it a variable, it will wait for this to be clocked out, and then read the returned value - of course this will be the byte you have just sent.
You want to do things the other way round, read what has been clocked to you, and then load the output buffer. spi_write, if called in an ISR, only loads the output buffer.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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