|
|
View previous topic :: View next topic |
Author |
Message |
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
MASTER SLAVE SPI PIC TO PIC PROBLEM |
Posted: Fri Apr 01, 2005 3:43 am |
|
|
Hello,
I use 2 PIC 18LF458 for an SPI communication.
I am just using this for th SLAVE :
Code: |
void main(void)
{
int8 data;
// SLAVE, Front n�gatif de CLK
setup_spi(SPI_SLAVE | SPI_L_TO_H | SPI_CLK_DIV_64);
//enable_interrupts(GLOBAL);
output_high(PIN_A5);
while(1)
{
data = spi_read(0xFF);
printf("data = %X", data);
delay_ms(1000);
}
}
|
And this for th MASTER :
Code: |
void main(void)
{
int8 data;
// MASTER, Front n�gatif de CLK
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
//enable_interrupts(GLOBAL);
while(1)
{
spi_write(0x01);
delay_ms(1000);
}
}
|
I have signals on the scope but i can't read on the SLAVE :
it seems that this is not working :
Quote: | data = spi_read(0xFF); |
Could you help me ? Thanks ! =) |
|
|
Ttelmah Guest
|
|
Posted: Fri Apr 01, 2005 4:57 am |
|
|
First comment, you don't need a clock rate on the slave settings. The slave is clocked by the master.
Now understand that SPI, sends a byte in both directions at once. When you 'SPI_WRITE' on the master, a byte is sent by the master, and anything waiting on the slave, is clocked back at the same time, and can then be read. The SPI_READ, with data, clocks out a byte, and reads the return. A _slave_ device, cannot generate a clock.
So something like this should work:
Code: |
void main(void)
{
int8 data;
// SLAVE, Front n�gatif de CLK
setup_spi(SPI_SLAVE | SPI_L_TO_H);
output_high(PIN_A5);
spi_write(0xFF);
//This puts a byte into the output buffer, for the master to receive
while(1)
{
if (SPI_DATA_IS_IN() {
data = spi_read();
spi_write(0);
//This will be received by the master on it's next transmission
printf("data = %X", data);
//No delay is wanted/needed. The transaction is synchronised
//by the master
//delay_ms(1000);
}
}
}
void main(void)
{
int8 data;
// MASTER, Front n�gatif de CLK
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1)
{
spi_write(0x01);
if (SPI_READ()==0) {
//The master now knows that the slave has seen the byte
//and can do something here...
}
delay_ms(1000);
}
}
|
I slightly "don't like", the way the standard SPI functions behave, and in the past have posted a set of macros, which seperate the behaviour into (to my mind) a 'better' logic for SPI communication.
Best Wishes |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Tue Apr 05, 2005 3:19 am |
|
|
I use this for the SPI which works very well, but now i want to write 2 or 3 times, and so read the 2 or 3 values.
For example, i want to write 0x01; 0x02 ; 0x03 and then read the values on the slave.
How can i synchronise the delay for the data (i know it is with the clock but how )?
Could someone help me ?
Code: |
void main(void)
{
int8 data;
// MASTER
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1)
{
output_high(PIN_A5);
spi_write(0x01);
output_low(PIN_A5);
delay_ms(20);
//if (SPI_READ()==0) {
//The master now knows that the slave has seen the byte
//and can do something here...
//}
}
}
|
Code: |
void main(void)
{
int8 data;
// SLAVE
setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
while(1)
{
if (SPI_DATA_IS_IN())
{
output_high(PIN_A5);
data = spi_read(0xFF);
printf("\nDATA = %X", data);
delay_ms(1000);
}
}
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Tue Apr 05, 2005 6:59 am |
|
|
global wrote: | I use this for the SPI which works very well, but now i want to write 2 or 3 times, and so read the 2 or 3 values.
For example, i want to write 0x01; 0x02 ; 0x03 and then read the values on the slave.
How can i synchronise the delay for the data (i know it is with the clock but how )?
Could someone help me ?
|
Code: |
void main(void) {
int8 count;
// MASTER
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1) {
output_high(PIN_A5);
spi_write(0xAA);
//allow enough time for slave to respond
delay_us(10);
if (spi_read(0x55)==0) {
//Here the slave has acknowledged the first marker byte
for (count=0;count<5;count++) {
delay_u(10);
spi_write(count);
}
}
output_low(PIN_A5);
//Here you have sent five bytes, that are now in the data array in the
//slave. Pause now, for the slave to do it's thing, and when this is
//finished, the slave will wait for another header.
delay_ms(2000);
}
}
void main(void) {
int8 data[5];
int8 count;
int8 state=0;
spi_write(0xff);
// SLAVE
setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
while(1) {
if (SPI_DATA_IS_IN()) {
switch (state) {
case 0:
if (spi_read(0)==0xAA) state=1;
break;
case 1:
if (spi_read(0)==0x55) {
state=2;
count=0;
//Show the header has been seen
output_high(PIN_A5);
}
break;
case 3:
data[count++]=spi_read();
if (count==5) {
spi_write(0xFF);
state=0;
output_low(PIN_A5);
//Signal you have received a block
//Here do what you want with the five bytes of data
}
else spi_write(0);
break;
}
//Same comment as before. You _must_ get rid of the delay
//in the slave. The transaction is synchronised by the master
//and if the slave waits longer than the gap between bytes
//from the master, data will be lost
//delay_ms(1000);
}
}
}
|
This is showing doing a five byte block, with a marker header (not needed if you are sure the bus is synchronised).
Best Wishes |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Tue Apr 05, 2005 7:10 am |
|
|
Thank you very much ! =)
WHere should i put the printf to see if it is read ?
Could you explain me a little bit more what you are doing here ?
Could you help me one last time ? =) |
|
|
Ttelmah Guest
|
|
Posted: Tue Apr 05, 2005 7:28 am |
|
|
Where I say 'do what you want with the five bytes of data'. At this point, you can print it, dance a jig, do anything you want...
There is a lot of data about the SPI hardware, in the MicroChip application notes. At the end of the day, you need to read about, and understand the interface first.
The code is pretty basic, if you understand that 'SPI_DATA_IS_IN', will only go true, when a byte has arrived, and not been read. You can therefore just wait in the slave for each byte, and read it in turn. The code was made more complex, by deliberately looking for a 'header', which allows the slave to know that it is receiving 'legitimate' data, and not just noise.
For what you are describing/asking so far, I have to ask 'why SPI'?. SPI is only really worthwhile, where large amounts of data need to transfer in both directions. For a simple 'master slave' data transfer, possibly with an answer, I2C is easier. Unfortunately, the high latency in the PIC interrupts, together with the lack of hardware byte searching, make the response time for an SPI slave very poor, restricting the utility of this interface as a slave...
Best Wishes |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Tue Apr 05, 2005 9:46 am |
|
|
Why can't i work it out whit this ? I should have 0x01 0x02 0x03 when i read on the slave...
Code: | void main(void)
{
//spi_master_write();
spi_slave_read();
}
void spi_master_write(void)
{
int8 data;
// MASTER
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1)
{
output_low(PIN_A5);
spi_write(0x01);
delay_cycles(20);
output_high(PIN_A5);
output_low(PIN_A5);
spi_write(0x02);
delay_cycles(20);
output_high(PIN_A5);
output_low(PIN_A5);
spi_write(0x03);
delay_cycles(20);
output_high(PIN_A5);
//if (SPI_READ()==0) {
//The master now knows that the slave has seen the byte
//and can do something here...
//}
}
delay_ms(1000);
}
void spi_slave_read(void)
{
int8 data;
// SLAVE
setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
while(1)
{
if (SPI_DATA_IS_IN())
{
output_low(PIN_A5);
data = spi_read(0xFF);
printf("\nDATA = %X", data);
output_high(PIN_A5);
}
delay_ms(2000);
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Tue Apr 05, 2005 2:58 pm |
|
|
It won't work for two reasons:
1) The damn delay in the slave!...
While the processor is delayed, any data received (except the last byte), will be lost. Your master is stopping for 20 machine cycles between bytes, your slave is stopping receiving for over 1 second.
2) The printf. This takes _time_ just like the delay. This is adding (depending on the baud rate), several more mSec, while the slave is not receiving.
If you want to do it like this, change the master to pause for 1 second between the bytes, and change the slave, to simply print the byte, and then return to the while loop. Since the bytes are sent every second, the slave will receive a byte, and print the message once per second.
Best Wishes |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Thu Apr 07, 2005 6:47 am |
|
|
Hello again Ttelmah I think this works =) :
Code: |
void main(void)
{
//spi_master_write();
spi_slave_read();
}
void spi_master_write(void)
{
// MASTER
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
while(1)
{
spi_write(0x01);
delay_ms(1000);
spi_write(0x02);
delay_ms(1000);
spi_write(0x03);
delay_ms(1000);
//if (spi_read()==0) {
//The master now knows that the slave has seen the byte
//and can do something here...
//}
}
}
void spi_slave_read(void)
{
int8 data;
// SLAVE
setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
while(1)
{
if (SPI_DATA_IS_IN())
{
output_low(PIN_A5);
data = spi_read(); // Get the data
delay_cycles(40); // Need a short delay to see pulse on scope
printf("\nDATA = %X", data);
output_high(PIN_A5); // Scope to see ints
}
}
} |
Thansk for your help !
Could you explain me what are he 0x55 and 0xAA you add in your code ? Is it for Configurate the registers or to intialize the SPI mode ? |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Apr 08, 2005 5:43 am |
|
|
Quote: | Could you explain me what are he 0x55 and 0xAA you add in your code ? Is it for Configurate the registers or to intialize the SPI mode ? |
Try reading a bit more carefull......
Quote: | This is showing doing a five byte block, with a marker header (not needed if you are sure the bus is synchronised). | 0x55 and 0xAA are just two random values used in the start of each message (header) so you can check the message is starting correctly.
Just for anyone interrested in using Ttelmah's code, there is a small bug in his example. In case of a corrupted message header he is not resetting the state machine. Current implementation will work, but is less save now.
change Code: | case 1:
if (spi_read(0)==0x55) {
state=2;
count=0;
//Show the header has been seen
output_high(PIN_A5);
}
break;
|
to Code: | case 1:
if (spi_read(0)==0x55) {
state=2;
count=0;
//Show the header has been seen
output_high(PIN_A5);
}
else // Error in receiving header
state = 0; // wait for first character of header again
break;
|
|
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Fri Apr 08, 2005 6:56 am |
|
|
Hello, thanks for youhelp everything is fine.
I need to write with data from the slave and read these data with the master.
In fact, i need to do the same thing that i have done but before the slave wrote and the slave read, now the slave write and then the master read the data.
Can i keep the master as master and slave as slave ?
I know that when i change the master to slave and slave to master it is working (it was predictible you'll say).
Anyway could someone help me to do this ?
It is returning 0xFF :
Thanks ! Code: | void main(void)
{
spi_master_write();
//spi_slave_read();
}
void spi_master_write(void)
{
int8 data;
// MASTER
//setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64 | SPI_XMIT_L_TO_H);
while(1)
{
//if (SPI_DATA_IS_IN())
//{
output_low(PIN_A5);
data = spi_read(0xFF);
printf("\nDATA = %X", data);
output_high(PIN_A5);
//}
delay_ms(2000);
}
}
void spi_slave_read(void)
{
int8 data;
// SLAVE
//setup_spi(SPI_SLAVE|SPI_SS_DISABLED);
setup_spi (SPI_SLAVE | SPI_H_TO_L | SPI_XMIT_L_TO_H);
while(1)
{
spi_write(0x01);
delay_ms(1000);
spi_write(0x02);
delay_ms(1000);
spi_write(0x03);
delay_ms(1000);
//if (spi_read()==0) {
//The master now knows that the slave has seen the byte
//and can do something here...
//}
}
}
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sun Apr 10, 2005 6:54 am |
|
|
You have the master to slave communication working, great!
In SPI communication only one device can be the master, this is decided at design time and never changed afterwards. Although it is technicaly possible to change a master to slave this is not good practice and will give you a lot of headaches because synchronization is going to be difficult (how and when to decide to switch from master to slave?).
What kind of data do you have to transmit? Is the slave always responding to a command from the master? Or is it possible the slave wants to initiate a data transfer without a prior master command? If yes, what response times?
It might even turn out SPI is not the right bus for your application. |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Mon Apr 11, 2005 1:21 am |
|
|
Hello,
data that i have to transmit are only bytes for the moment but for example the slave should initiate the master with sending 0x02 to the master for the master to execute some commands.
I must be able to read and write on the slave as i must do it on the master. Commands could be from the master as well as from the slave.
The slave wants to initiate a data transfer without a prior master command, yes and it should be as fast as possible !
Some people already told me that SPI may be not the right bus for this application, but i want to know if there is any solution for that first before maybe change my point of view.
I need to know if my code could be writtable to only WRITE WITH THE SLAVE AND READ WITH THE MASTER !
Maybe you could give me some solutions or others ways to do what i want to do ...
Thanks a lot. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Apr 11, 2005 4:28 pm |
|
|
Quote: | The slave wants to initiate a data transfer without a prior master command, yes and it should be as fast as possible ! | This won't be easy with SPI. I never had to implement something like that and am not sure what is the best solution.
One way to implement this with SPI is to add an extra signal line from slave to a master interrupt input. When the slave wants to initiate a data transfer it sends the interrupt signal to the master. Problem in this setup is the situation where both the master and slave want to start communications simultaneously, your protocol has to take care of this.
You didn't tell us enything about your application, maybe other solutions are possible. Why did you choose your current master to become the master? Maybe switching the master and slave role is a better solution?
I don't know enough of I2C, but this might be a better bus for your purpose as it allows for multiple masters. Maybe someone else can jump in here? |
|
|
global
Joined: 01 Feb 2005 Posts: 21 Location: Paris
|
|
Posted: Tue Apr 12, 2005 2:07 am |
|
|
Hello,
could you help me with a code example using interrupts to do what i want to do ?
I may need a briefing on the interrupts i never used it before and i want to learn.
It is a project designed by other people, i just try to get where they want to go !
Anyway, it seems strange that i can write with the master and read with the slave and NOT write with the slave and read with the master ... It seems to be possible, but why can't we ?
Thanks again for your help. If someone could do something more ? |
|
|
|
|
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
|