|
|
View previous topic :: View next topic |
Author |
Message |
john.ma
Joined: 19 Nov 2012 Posts: 23
|
Interrupt based SPI routine - PIC24F - Issue receiving data |
Posted: Tue Jan 29, 2013 4:33 pm |
|
|
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
|
|
Posted: Wed Jan 30, 2013 3:13 am |
|
|
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
|
|
|
john.ma
Joined: 19 Nov 2012 Posts: 23
|
|
Posted: Thu Jan 31, 2013 12:14 pm |
|
|
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
Thanks,
John |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1346
|
|
Posted: Thu Jan 31, 2013 7:18 pm |
|
|
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
|
|
Posted: Fri Feb 01, 2013 2:58 am |
|
|
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
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
|
|
Posted: Fri Feb 01, 2013 3:51 am |
|
|
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
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
|
|
Posted: Fri Feb 01, 2013 5:31 pm |
|
|
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
|
|
Posted: Fri Feb 01, 2013 7:17 pm |
|
|
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
|
|
Posted: Fri Feb 01, 2013 7:19 pm |
|
|
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
|
|
Posted: Fri Feb 01, 2013 7:32 pm |
|
|
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
|
|
Posted: Sat Feb 02, 2013 12:20 pm |
|
|
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
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
|
|
Posted: Sat Feb 02, 2013 12:54 pm |
|
|
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
|
|
Posted: Sat Feb 02, 2013 12:59 pm |
|
|
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
|
|
Posted: Sat Feb 02, 2013 3:02 pm |
|
|
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 |
|
|
|
|
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
|