|
|
View previous topic :: View next topic |
Author |
Message |
natapongw
Joined: 19 Apr 2011 Posts: 7
|
SPI PIC to PIC 16F690 read from slave problem |
Posted: Thu Apr 21, 2011 1:15 am |
|
|
Hi,
I write some SPI PIC to PIC interface and success data write to slave but master can't get data from slave
Are anyone have some sample code for PIC16F for example or any suggestion ?
Best regards,
my code
master
Code: | #include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)
#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)
#define SS_PIN PIN_C6
void main() {
int data;
//The next statement sets up the SPI hardware, with this PIC as a master using mode 1
//SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
delay_ms(100);
output_high(SS_PIN);
while(true) {
output_low(PIN_C6);
data=0;
spi_write(0x18);
spi_write(1);
data=spi_read(0);
output_high(PIN_C6);
delay_ms(1000);
printf("V1=%x\n\r",data);
}
} |
slave
Code: | #include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)
#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)
int8 memory[80], data, instr, address;
void write_data(void)
{
while(!spi_data_is_in());
data = spi_read();
if(address >= 0 || address <= 80)
{
memory[address] = data;
}
}
void main(void)
{
setup_spi(spi_slave | spi_l_to_h | spi_ss_disabled);
while(true)
{
while(!spi_data_is_in());
instr = spi_read();
while(!spi_data_is_in());
address = spi_read();
if (instr == 0x18)
{
instr = spi_read(18);
}
else if(instr == 0xa)
{
write_data();
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Thu Apr 21, 2011 2:10 am |
|
|
Enable Slave select, and have the master send a select signal.
Problem is that without SS, it is very difficult to synchronise the two chips when they wake up. If the master wakes earlier or latter than the slave, there is a very good chance of a 'random' extra clock bit at the start of the transmission. Once you have this, the buses will remain permanently 'out of sync'.
Without SS. you need to have the clock line biased to a level (say high), and have the master pull it low for a period when it wakes, then start the SPI peripheral. On the slave, you need to have it watch the line, and wait for it to go low, and only then start the SPI peripheral. You also need to have something like a checksum in the data, and the slave respond with a bit pattern to the master. If the master sees the wrong bit pattern, and the slave sees the wrong checksum, you re-initialise the bus.
SPI without SS, is quite hard to do.
Best Wishes |
|
|
natapongw
Joined: 19 Apr 2011 Posts: 7
|
|
Posted: Thu Apr 21, 2011 2:31 am |
|
|
Thank you very much Ttelmah
I try for many code but still can't get data from slave.
Now I remove "spi_ss_disabled" and it not work.
Screen not show anything when run but when send data to slave it's work. |
|
|
natapongw
Joined: 19 Apr 2011 Posts: 7
|
|
Posted: Thu Apr 21, 2011 2:59 am |
|
|
Do I need some resistor in bus line ? |
|
|
natapongw
Joined: 19 Apr 2011 Posts: 7
|
|
Posted: Thu Apr 21, 2011 6:01 am |
|
|
I can get value now !
I use "output_high(PIN_C6);" that is ss pin before loop in slave PIC.
But my new problem when I try to get data from array in slave it is incorrect more than correct data. |
|
|
natapongw
Joined: 19 Apr 2011 Posts: 7
|
|
Posted: Thu Apr 21, 2011 6:11 am |
|
|
I found that every 3 loops data will correct here is my code
Master :
Code: | #include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)
#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5,bits=8, errors)
#define SS_PIN PIN_C6
//————————————————————————————————————————————————————————————
void main() {
int8 data,inp,loop;
//The next statement sets up the SPI hardware, with this PIC as a master using mode 1
//SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
delay_ms(100);
output_high(SS_PIN);
data=0x00;
while(true) {
for(loop=0;loop<=1000;loop++){
for(data=0;data<10;data++){
output_low(SS_PIN); //pull the slave select line low to select the slave
delay_us(10); //give the slave time to notice this (may be unnecessary)
spi_write(data); //send the value
//if(spi_data_is_in())
delay_us(loop);
inp=spi_read(0);
delay_us(10); //(may be unnecessary)
output_high(SS_PIN); //deselect the slave.
delay_ms(200);
printf("V%d=%d\n\r",loop,inp);
}
}
}
} |
Slave
Code: | #include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)
#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)
int8 gps[10]={1,3,3,6,122,1,2,4,7,3};
int val;
#int_ssp
void ssp_isr(void)
{
disable_interrupts(INT_SSP);
val = spi_read(0);
while(!spi_data_is_in())
spi_write(18);
enable_interrupts(INT_SSP);
}
void main(void)
{
//printf("Begin\n\r");
setup_spi(SPI_SLAVE | SPI_L_TO_H);
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
output_high(PIN_C6);
while(true)
{
//val = spi_read(0); //spi_read must be passed an argument. The argument value is sent
//back to the master whenever the master sends us a message again.
//This allows two-way communication, but here the master ignores
//whatever the slave sends back, so just send a 0.
//spi_write(gps[val]);
//display the value read:
//printf("Data : %u\n\r", val);
}
} |
And this is my result
V0=18
V0=3
V0=4
V0=18
V0=6
V0=7
V0=18
V0=9
V1=0
V1=18
V1=2
V1=3
V1=18
V1=5
V1=6
V1=18
.
.
.
. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Thu Apr 21, 2011 10:13 am |
|
|
Don't disable the interrupt in the handler. Not needed, the hardware disabled interrupts for you.
You are mishandling the byte order. When the slave interrupt triggers, _one_ byte is waiting to be read. You are attempting to read this, then write another byte 'out', then waiting for a second byte to arrive.
Code: |
//slave
#int_ssp
void ssp_isr(void)
{
val = spi_read(); //Do _not_ try to send a value here on a slave
spi_write(val+1); //This is the byte that will be received by the master on
//it's _next_ transaction
}
|
Code: |
//master
#define SS_PIN PIN_C6
//————————————————————————————————————————————————————————————
void main() {
int8 data=0,inp;
//The next statement sets up the SPI hardware, with this PIC as a master using mode 1
//SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
output_high(SS_PIN);
delay_ms(1);
do {
//You declared loop as an int8. How can it count to 1000?....
for(data=0;data<10;data++){
output_low(SS_PIN); //pull the slave select line low to select the slave
spi_write(data); //send the value
output_high(SS_PIN);
delay_us(70); //Allow time for the interrupt to be serviced - typically
//60+ instructions
output_low(SS_PIN);
inp=spi_read(0);
output_high(SS_PIN);
delay_ms(200);
printf("V%d=%d\n\r",inp);
}
}while(TRUE); //avoids warning message
}
|
Should give 1 to 11 as replies.
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
|