|
|
View previous topic :: View next topic |
Author |
Message |
Chard
Joined: 01 Jun 2017 Posts: 4
|
SPI Master Slave Problem w/ 876's |
Posted: Thu Jun 01, 2017 4:42 pm |
|
|
Hello, I have been fighting this problem for a couple of days and was wondering if you can help. I am using the latest Demo Version with 3 days left and using SPI (to) Master / Slave with two PIC16F876's. The slave has a 555 timer hooked to CCP1 with a 1kHz square and it reads the correct value to send to Master, but Master always gives me incorrect value. The wiring, pinouts and clock signals all check out so I figured there is something wrong with my code.
MASTER
Code: |
#include <HWspiMaster.h>
#use spi (MASTER, SPI1, ENABLE=PIN_A5, BAUD=9600, MODE=0, BITS=16, STREAM=SPI_STREAM)
#define CLRuart() while(kbhit())ch=getc()
void main()
{
unsigned long value;
//byte lowbyte;
//byte highbyte;
char ch;
printf("SPI Test\r\n");
delay_ms(500);
port_b_pullups(TRUE);
printf("IPL Complete\r\n");
delay_ms(1000);
while(TRUE)
{
if(kbhit())
ch=getch();
ch=tolower(ch);
if(ch=='t')
{
value=spi_xfer(SPI_STREAM,0x00,16);
printf("Freq = %lu\r\n",value);
} // ends if
CLRuart();
ch='&';
delay_ms(1000);
} // ends while
}
|
SLAVE
Code: |
#include <HWspiSlave.h>
#use spi (SLAVE, SPI1, ENABLE=PIN_A5, MODE=0, BITS=16, STREAM=SPI_1)
#include "count.c"
unsigned long result;
#INT_SSP
void SSP_isr(void)
{
printf("Data sent = %lu\r\n",result);
spi_xfer(SPI_1,result,16);
}
#INT_CCP1
void CCP1_isr(void)
{
;
}
void main()
{
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
result=0;
printf("IPL Complete\r\n");
while(TRUE)
result = count(PIN_C2, 1000); // count period = 1000 ms
} |
Do you see any blatant errors? Thank you in advance. 'Chard |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9253 Location: Greensville,Ontario
|
|
Posted: Thu Jun 01, 2017 6:07 pm |
|
|
I'd get rid of the printf inside the ISR in the Slave code, recompile, retest, report back .......
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Fri Jun 02, 2017 1:45 am |
|
|
Also you need to understand SPI....
Your hardware only transfers 8bits at a time (though the compiler will attempt to handle 16bits for you, there are still difficulties about this).
On the slave, the data to send has to be loaded into the buffer _before_ the master requests it. The master then receives the byte that is loaded, when it sends it's first byte, and the slave has to load the second byte before the master tries to transfer the next byte. This is the first problem about 8bit. The master needs to pause long enough between byte #1, and byte #2, for the slave to load the second byte. using the combined 16bit transfer at the master, doesn't allow such time.....
Then you have the problem of needing to load the data 'in advance'. This is why normally the master would transmit a byte, _before_ trying to receive. This then triggers the interrupt, allowing the slave to 'pre-load' the first byte.
The slave interrupt is 'per byte' (on your chip), and the compiler can't change this.
You don't show us your clock rates. Generally it'll take about 40 instructions for the slave to have loaded a byte ready to transfer.
Look at the example. EX_SPI_SLAVE.C
Understand that the slave has to read the byte that has arrived in the interrupt, and then if it is doing a write, load the next byte to send. This is the 'spi_prewrite()' function. You can get rid of the address handling in this, but should still have the single byte command to trigger the slave to load the value to send. |
|
|
Chard
Joined: 01 Jun 2017 Posts: 4
|
|
Posted: Fri Jun 02, 2017 3:41 am |
|
|
Thank you for the expedient reply,Ttelmah and temtronic. I removed the printf from the ISR with same results. When this triggers it should send the
result that has been aquired, yes? spi_xfer(SPI_1,result,16);
Whether the result is 0x3e8 ( 1000 hz ) or even zero (if thats what the data is). I just get random values. The master code uses
Code: | value=spi_xfer(SPI_1, 0x00, 16); |
Which sends a zero to trigger the slave ISR. Am I correct in assuming this?
My clock speeds are Master 14.31818 Mhz and Slave 4.096 Mhz which are the only two crystals I had left for these 876's. I will look at the example and try some 8 bit transfers (again). Gracias Mucho, Amigos, for the advice. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Fri Jun 02, 2017 4:25 am |
|
|
Slave at about 1/4 the speed of the master. The master is going to have to pause for about 40uSec between asking for byte 1 and byte 2. You need to think again about your transfer. So something like:
Master issues a dummy byte.
Waits 50uSec.
This triggers the slave interrupt, and the reads the dummy byte, and then loads the first byte to send (understand what I said. The _hardware_ only supports 8 bits at a time).
Master clocks out a second byte, and receives the first byte from the slave. This also triggers a second slave interrupt. The slave again reads the byte, and loads the second byte to send. Master again waits for this to happen.
Master clocks out third byte, and receives the second byte.
So something like:
Code: |
//SLAVE
unsigned long result;
#INT_SSP //This is always a _byte_ transaction
void SSP_isr(void)
{
static int8 doing=0;
int8 dummy;
//slave reads the byte it has just been sent
dummy=spi_xfer_in(SPI_1,0,8);
if (doing==0)
{
spi_prewrite(SPI_1,make8(result,1)); //Load LSB
if (dummy==0) //master has sent '0' marking this as a 'start'
doing=1;
}
else if (doing==1)
{
spi_prewrite(SPI_1,make8(result,0),8); //load 8bits LSB
doing=2;
}
else if (doing==2)
{
spi_prewrite(SPI_1,1); //dummy
doing=0;
}
}
//MASTER
int16 get_value(void)
{
int16 temp;
int8 dummy;
//Now need to trigger the transfer
dummy=spi_xfer(SPI_1,0,8); //The '0' marks a start
//wait for the slave to load the first byte
delay_us(50);
dummy=spi_xfer(SPI_1,1,8); //clock the first byte back
//this automatically loads the second byte
delay_us(50);
temp=make16(dummy,spi_xfer(SPI_1,1,0); //and the second
return temp;
}
|
Key points to understand:
1) The hardware only supports 8bit transfers. Doesn't matter for the master, you can 'string' together multiple transfers (which is what the compiler does), but does for the slave. PIC24's and 32's do support 16bit hardware transfers. Your chip doesn't.
2) You don't get back what the slave has just loaded. You get back the _last_ byte the slave loaded. Hence you need to trigger the transfer by sending a dummy byte. Though data is sent both ways at once , the data you receive is always a 'reply'.
3) The problem of time. Because of the response nature, the slave has to have time to load it's reply, _before_ you ask for the next byte. The high speed 'strung together ' 16 or 32bit transfers are for use with _hardware_ where the data can all be ready to reply. Especially because your slave is so slow, you need to allow for this.
You also need to consider what happens if the slave changes the 'result' while a transfer is taking place. You need to handle this. |
|
|
Chard
Joined: 01 Jun 2017 Posts: 4
|
|
Posted: Fri Jun 02, 2017 8:42 am |
|
|
Thank you Ttelmah for this explanation. I will give your sample code a try
and keep messing with it until this trial version runs out. I will either just rewrite this (all) in Hitech C or MikroC and give that a try for this 8 channel Cable/Capacitance tester. May even use two 887's and the PSP port for transfer if I keep getting grief like this. I just want to get this Finished !
You know, us Gemini's are short on patience....Har ! ( No....DOUBLE Har ! )
Thanks again, Ttelmah. 'Chard |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Fri Jun 02, 2017 8:56 am |
|
|
Seriously CCS C, is by far the easiest C to use on the market.
However you do need to understand what the hardware can do. |
|
|
Chard
Joined: 01 Jun 2017 Posts: 4
|
|
Posted: Fri Jun 02, 2017 12:08 pm |
|
|
Yes, I agree its a great product and definitely on my hit list, but this
was a bit misleading
result = spi_xfer(stream, data, bits)
I was under the impression that this function did all the legwork to
acquire 16 bits if that was the parameter passed to it. The manual made no
reference to making multiple calls for the result, much less the data type
returned, which is why I declared an unsigned long when asking for 16 bits
in the stream. I did do some scouring on the web but a lot of information I got was a bit outdated, along with compiler versions. That is probably why I interpreted this function the way I did.
Anyway, enough "Hamming and Hawing", I appreciate your efforts and responses. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19561
|
|
Posted: Fri Jun 02, 2017 1:04 pm |
|
|
It does.
For the master, talking to SPI hardware, where the hardware has the data 'preloaded' into a 16bit register you can clock the data from. In other words, most SPI peripheral chips.
Problem is you are talking to a slave, that only has an 8bit register. |
|
|
|
|
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
|