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

SPI connection between PIC18F6723 and PIC18F4523

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Holger
Guest







SPI connection between PIC18F6723 and PIC18F4523
PostPosted: Sat Oct 25, 2008 9:17 am     Reply with quote

Hello,

I'm using CCS 4.068 and trying to connect two PIC via SPI. I defined the PIC18F6723 as Master using SPI2 (SPI1 is not connected to the second PIC). The PIC18F4523 is configured as Slave and there are no more slaves on the bus.
After starting first the Master and then the Slave (first the slave and then the master results in a bit shift of the byte the slave gets), the slave is receiving the bytes from the master in a correct way.
But now my problem is, that I am sending this byte added by 2 (for testing) back to the master, but the master receives the same byte as he had send to the slave. It seams as if the master is reading its own byte. By sending a "a" to the slave the slave receives the "a" he now should send a "c" but the master receives a "a".

What am i doing wrong?

Code Master:
Code:

#include <18F6723.h>

#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES PUT                      //Power Up Timer

#define crystal 10000000
#use delay(clock = crystal)

#use rs232(baud=9600, parity=N, xmit=PIN_G1, rcv=PIN_G2, bits=8, stream=DEBUG)

#define PIC2_DI     PIN_D4
#define PIC2_DO     PIN_D5
#define PIC2_CLK    PIN_D6

#define StatusLED PIN_F2

void main()
{
   char c,b;
   setup_spi2(SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);
   output_bit(StatusLED,0);
   delay_ms(1000); 
   output_bit(StatusLED,1);
   
   output_low(PIC2_DI);
   output_low(PIC2_CLK);

   while(1) { 
      if(kbhit()) {  // Char available from PC ?
         c = getc();  // If so, get it       
         spi_write2(c);
         while(!spi_data_is_in2());
         b=spi_read2(0);
         putc(b);
      }
   }
}


Code Slave:
Code:

#include <18F4523.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES PUT                      //Power Up Timer
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=10000000)

#define StatusLED PIN_C0

#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, stream=DEBUG)

void main(void)
{
   int8 c, b =65;
   int8 i;
   
   setup_spi(SPI_SLAVE | SPI_H_TO_L |SPI_SS_DISABLED);
   output_bit( StatusLED, 0);
   delay_ms(1000);
   output_bit( StatusLED,1);
   
   while(true){
      while(!spi_data_is_in()); 
      c = spi_read();
      spi_write(c+2);
      putc(c);
   }
}
Guest








PostPosted: Sat Oct 25, 2008 9:33 am     Reply with quote

Timing.
When the spi port sends a byte, one is received back _at the same time. Hence your test for data received, will immediately return 'true'. Then the Master clocks out another dummy byte, and reads the return, but with no time allowed for the slave to have actually loaded the return.
The master is in control of the bus, and bytes cannot be received, without it clocking them. Clock out the first byte, then wait for this to be sent (just use the SPI_read function). Then _wait_ for the slave to load the reply, and clock this back. So:
Code:

//Master
   while(1) {
      if(kbhit()) {  // Char available from PC ?
         c = getc();  // If so, get it       
         b=spi_read2(c);
         //Using the read, ensures the byte has actually sent
         delay_us(10);
         b=spi_read2(0);
         putc(b);
      }
   }

Make the wake up delay on the slave, shorter than on the master.
Don't fiddle with the SPI pins yourself. Let the hardware handle them.
In the slave, you will need to throw away the dummy character, before looping to wait for the next incoming one.

Best Wishes
Holger
Guest







PostPosted: Sat Oct 25, 2008 9:52 am     Reply with quote

I have already tried to send the byte first, then wait 50ms and read (and resending it) again. But unfortunately it did not work.
Code:

c = getc();       
b=spi_write2(c);
delay_ms(50);
b=spi_read2(c);
putc(b);
Ttelmah
Guest







PostPosted: Sun Oct 26, 2008 4:30 am     Reply with quote

OK.
Reading it's 'own byte', is not that abnormal. The register used is the same both ways. That it is happening even with a delay, suggests possibly that the CCS code is doing something 'screwy', and not actually performing the second write...
On your 'wake up' bit shift, this is because of the polarity selected for the data. the slave sees the edge when the master enables the bus, and clocks a spurious bit in at this point.
Have the slave 'poll' the SCLK input, and check the master is driving it, _before_ it enables the SPI hardware.

Historically, I don't 'like' the CCS SPI functions. For my money, they are incorrectly written, for handling the SPI hardware, especially in interrupt driven applications. In such an application, on the slave, you want to just read the SPI data register in the handler ASAP (he CCS code adds lots of testing), and in the master, you want to load the register (again without testing), and do other things till the hardware signals it has completed the job. The SPI_DATA_IS_IN function has improved things a lot.
Therefore, I always use my own functions. So, let's try proving if the problem is hardware or software, and use these instead:
You still need to use the CCS initialisation, and I'd test the SCLK line on the slave, and wait for this to go high, before enabling the hardware here.
Code:

#byte   SSPBUF = 0xFC9
#byte   SSPSTAT = 0xFC7

#byte   SSPBUF2 = 0xF66
#byte   SSPSTAT = 0xF64

/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE READ_SSP()   (SSPBUF)
#DEFINE SSP_HAS_DATA ((SSPSTAT &1)!=0)
#DEFINE   WAIT_FOR_SSP()   while((SSPSTAT & 1)==0)
#DEFINE   WRITE_SSP(x)   SSPBUF=(x)
#DEFINE READ_SSP2()   (SSPBUF2)
#DEFINE SSP2_HAS_DATA ((SSPSTAT2 &1)!=0)
#DEFINE   WAIT_FOR_SSP2()   while((SSPSTAT2 & 1)==0)
#DEFINE   WRITE_SSP2(x)   SSPBUF2=(x)

//Master
int8 dummy;

c=getc();
if (SSP2_HAS_DATA) dummy=READ_SSP2(); //Ensure SSP is empty

WRITE_SSP2(c);

WAIT_FOR_SSP2(); //Ensure transaction has completed
dummy=READ_SSP2(); //Empty buffer

delay_us(20); //Give slave time to load reply

WRITE_SSP2(0);

WAIT_FOR_SSP2(); //Ensure transaction has completed
c=READ_SSP2(); //Get reply

//Slave
while(true){
   WAIT_FOR_SSP();
   c = READ_SSP();
   WRITE_SSP(c+2);
   putc(c);
   WAIT_FOR_SSP(); //Wait for the master to receive the byte sent
   c=READ_SSP(); //Clear the buffer here, so I can wait for the next byte
}

Now several things here are not necessary (you don't need to empty the buffer in the master etc.), but it should be 'dead safe', and prove whether the hardware works.

Best Wishes
Holger
Guest







PostPosted: Sun Oct 26, 2008 5:27 pm     Reply with quote

Thank you for the help.

Just for others reading the code from Ttelmah there is a small writing mistake in the code:
#byte SSPSTAT = 0xF64

should be

#byte SSPSTAT2 = 0xF64

At the moment I can send characters to each PIC but they are corrupted (every time I start the board) . How can I synchronize the two pic's so they do not have a byte shift or other effects?
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Sun Oct 26, 2008 6:34 pm     Reply with quote

Holger wrote:
Thank you for the help.
...At the moment I can send characters to each PIC but they are corrupted (every time I start the board) . How can I synchronize the two pic's so they do not have a byte shift or other effects?

Whenever you use SS disabled on the slave, it is always possible to get out of sync and stay out of sync. This would happen, for example, if the master started sending a byte before the slave was powered up and out of reset. The slave might see a portion of a byte. One solution is to implement SS. Use a general purpose output from the master and wire it into the SS input on the slave. Whenever you lower SS, the bit counter on the slave is reset. If you can't use SS on the slave, then you might consider forcing a reset of the bit counter on the slave at a time in the protocol when you are fairly sure the master is not transmitting. Timing a short time-out after the reception of a byte could work. Make sure the time-out is long enough to cover one full byte. To reset the bit counter, disable the SPI port and re-enable it. You don't need to call any CCS functions. Just clear SSPCON.SSPEN and then set it again.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah
Guest







PostPosted: Mon Oct 27, 2008 3:12 am     Reply with quote

Yes.
The other 'route', not using an extra line, is to ensure that at some point in your 'comms', there is always a period where nothing happens. Have you comm 'packet', have an identifiable 'header' pattern (perhaps something like 0xAA 0x55). Have a 'resync' function, in the slave, which turns off the SPI hardware, then waits for the 'idle' period, and re-enables it. Call this at the start to get the system 'in sync', and call it again, if you do not see the 'header' pattern where you expect it.
Using an extra line is really easier and quicker.
Sorry about the 'typo'....

Best Wishes
Holger
Guest







PostPosted: Mon Oct 27, 2008 9:50 am     Reply with quote

Hello,

Thank you all, unfortunately I have and had the SS wire connected. But as I am just testing only 1 Slave at the SPI line, I thought I would start the test program as simple as possible and decided not to use the SS as I do not have to select between slaves.
I had not suspected that this simplification made it more complicated :-)

Now the two PIC's communicate without any problems, Thanks.

@Ttelmah
I have seen your Macros for the SPI communication in other threads to. But there always was 1 more definition #define CLEAR_WCOL() SSPCON = SSPCON & 0x3F. What is this for?
Ttelmah
Guest







PostPosted: Tue Oct 28, 2008 4:09 pm     Reply with quote

Clears the write collision bit.
Only gets set if you write directly to the buffer, without testing that a transmission has completed.

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
Page 1 of 1

 
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