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

Trouble with SPI!!!

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



Joined: 31 May 2007
Posts: 11

View user's profile Send private message

Trouble with SPI!!!
PostPosted: Tue Jul 29, 2008 2:04 pm     Reply with quote

Hi:

·I'm having a weird problem with SPI communication. I've got a PIC as a transmitter in slave mode; it sends a fixed string thru SPI. The master receives the SPI data and sends it to a PC via USART, in this case just to check if the SPI is being received alright. Problem is, when using SPI_L_TO_H, it works just fine. But when i changed it to SPI_H_TO_L, the output is wrong. Actually, the data looks misaligned to the clock (i'm looking it with an oscilloscope). For example:

*If i send periodically 86 (01010110), what i get in my terminal is
172 (10101100).

*If i send periodically 240 (11110000), what i get in my terminal is
225 (01111000).

·It's as if the bytes are shifted in one bit, that's what it looks like when looking at the scope.

·The code for the slave:

Code:

#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=2400, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)

//////////////////
// DEFINICIONES //
//////////////////

#define nop   delay_cycles(1)
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

////////////////////
// INTERRUPCIONES //
////////////////////

#int_timer2
void timer2_isr(void)
{
   int16 ctr;   

   ctr++;

   if(ctr==620)
   {
      output_toggle(PIN_C2);
      ctr = 0;
      nop;
   }   
}

#int_rda
void UART_isr(void)
{   
   putc(getc());
}

//////////////////////
// RUTINA PRINCIPAL //
//////////////////////

void main(void)
{
   int i;
   char string[32] = "Simulador TX Serial Sincrónica";

   setup_timer_2(T2_DIV_BY_16, 130, 1);
   setup_spi(SPI_SLAVE|SPI_MODE_2|SPI_SS_DISABLED);

   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_RDA);   
   enable_interrupts(GLOBAL);

   while(1)
   {
      //String que se repite periódicamente

      i = 0;

      while(string[i]!=0)      
      {         
         spi_write(string[i]);
         i++;
      }
      
      //spi_write(0xF0);

      //CR LF

      spi_write(0x0D);
      spi_write(0x0A);

   }
}


·The code for the master:

Code:

#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=2400, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)

//////////////////
// DEFINICIONES //
//////////////////

#define nop   delay_cycles(1)
#define SPI_MODE_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1  (SPI_L_TO_H)
#define SPI_MODE_2  (SPI_H_TO_L)
#define SPI_MODE_3  (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#byte PORTB = 0x0F81

////////////////////////
// VARIABLES GLOBALES //
////////////////////////

int data;
int changes = 0, last_b = 0b10000000;
short RTS = 0;
short SPI = 0;

////////////////////
// INTERRUPCIONES //
////////////////////

#INT_RB
void portb_isr(void)
{
   changes = last_b ^ PORTB;
   last_b = PORTB;

   //Canto de bajada en PIN_B7 (baja a 0 V)
   if (bit_test(changes,7)&& !bit_test(last_b,7))

      RTS = 1;
   
   //Canto de subida en PIN_B7 (sube a 5 V)
   if (bit_test(changes,7)&& bit_test(last_b,7))

      RTS = 0;   
   
   //Debouncer
   delay_us(100);
}

#INT_TIMER2
void timer2_isr(void)
{
   int16 ctr;

   ctr++;

   if(ctr == 1250)
   {
      output_toggle(PIN_C2);
      ctr = 0;
   }   
}

#INT_SSP
void SPI_isr(void)
{
   if(spi_data_is_in())   
      SPI = 1;
}

////////////////
// PROTOTIPOS //
////////////////

int fix(int data);

//////////////////////
// RUTINA PRINCIPAL //
//////////////////////

void main(void)
{
   data = 225;
   data = fix(data); //should be 240
   data = 172;
   data = fix(data); //should be 86

   setup_timer_2(T2_DIV_BY_16, 130, 1);
   setup_spi(SPI_MASTER|SPI_MODE_2|SPI_CLK_T2);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RB);
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_SSP);   

   while(1)
   {
      while(RTS)
      {   
         spi_write(0x40);

         if(SPI)
         {
            data = spi_read();            
            putc(fix(data));
            SPI = 0;
         }

      }
   }
}


int fix(int data)
{
   int aux;

   if(bit_test(data,0))
      aux = 0x80;
   else
      aux = 0;

   data >>= 1;
   data |=  aux;
   
   return(data);
}


·The master generates a 1200 Hz clock (i need to interface with a 1200 bps synchronous device). If it receives a high to low signal on pin B7, it generates a clock signal, then sends to the usart the data read thru SPI.

·BTW, the "fix" function is a cheap attempt to undo the shift that the byte suffered. When using SPI_L_TO_H i didn't use it, as it worked alright.

·In both cases i'm using the pin C2 as an "i'm alive!" indicator, specially in the slave.

·Any help will be appreciated, as i'm really confused about what's happening here.

Thanks in advance!!
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Wed Jul 30, 2008 8:06 am     Reply with quote

It sounds like you have the wrong SPI_MODE, i.e. you are sampling on the wrong clock edge.
_________________
The search for better is endless. Instead simply find very good and get the job done.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jul 30, 2008 5:15 pm     Reply with quote

I agree with SherpaDoug that it sounds like a problem with the SPI mode.

Why are you using the SSP interrupt in the master? In this simple test program the test in main
Code:
 if(SPI)
can be replaced by:
Code:
   if(spi_data_is_in())
and then the SSP interrupt can be removed.

Hint: add the NOLVP fuse to your program for improved stability. 99% of the people are using a 'high voltage programmer' and with the NOLVP fuse missing the PIC will stall when the LVP pin goes high (static voltage, etc.).

What is your compiler version?
FoxtrotMike



Joined: 31 May 2007
Posts: 11

View user's profile Send private message

PostPosted: Mon Aug 11, 2008 9:35 am     Reply with quote

Thanks for your help, guys.

*ckielstra: I removed the interrupt, as it really served no purpose. Also, i added a little delay between every spiread() call, and of course, i removed the "fix". It seems to be working now. However, I noticed that between every byte there's a longer clock pulse. It's like there's a small delay between every two bytes received. Something like this (sorry for the crude ASCII "art"):

Code:

CLK

 b1  b2     b8
 ┌-┐ ┌-┐   ┌--┐ ┌-┐ ┌-┐
-┘ └-┘ └···┘  └-┘ └-┘ └···
            ^
           /_\
Longer   ---┘
clock
pulse


·Any idea why is this happening? I believe it's disrupting the communication with the slave device, as it's very sensitive to clock drift.
Ttelmah
Guest







PostPosted: Mon Aug 11, 2008 9:48 am     Reply with quote

The master can't load new data, till the last byte has been sent. This takes time.
SPI, shouldn't have any issues with 'clock drift'. The master generates the clock as it sends the data.
Use

data=spi_read(0x40);

This will remove the need to wait for the byte to be sent, and then check again that the buffer is full to receive the byte.

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