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 read/write problem

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



Joined: 04 May 2009
Posts: 35
Location: India

View user's profile Send private message

spi read/write problem
PostPosted: Thu Jul 15, 2010 2:51 am     Reply with quote

Hi,
I am using a master/slave architecture two transfer a 10-bit data from master (16F876A) to slave (16F72) via SPI.

The main purpose of this project is to read voltage from ADC and transmit the read data to slave to display the read voltage on 7-Segment.

The problem I am facing here is that I am not getting the same data on the receiver's side. For example if I am sending 1023 (300V) from master's side I am receiving 770 (226V) on receiver's side.

Please help me guys.

master
Code:

//master.c

#include <16f876A.h>
#device adc=10
#include <timers.h>

#USE DELAY( CLOCK=4000000 ) /* Using a 4 Mhz clock */
#FUSES XT,NOWDT,NOPROTECT,NOPUT
int16 result=0;

void transmitData(void);
void getVoltage(void);
void spi_write16(int16 data);

//-------------------------------------------------------------------
// The rtcc interrupt occurs when the rtcc rolls over from FF to 00.
// I have programmed it to interrupt at a 100 Hz rate.
//
// RTCC interrupt rate = Fosc / (4 * rtcc pre-scaler * rtcc pre-load)
//
//                     = 4 MHz / (4 * 256 * 39)
//
//                     = 100.16 Hz
//
// This gives us a timer tick approx. every 10 ms  (9.98 ms actually).
//-------------------------------------------------------------------
#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);

// Decrement any timers that are running.

if(gc_transmit_timer)
   gc_transmit_timer--;
}

//--------------------------------------------------------

void main()
{
   setup_counters(RTCC_INTERNAL,RTCC_DIV_256);    
   enable_interrupts(INT_RTCC);
   enable_interrupts(GLOBAL);

   setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 );
   setup_adc_ports(AN0_AN1_AN3);
   setup_adc(ADC_CLOCK_DIV_64);

   set_tris_a(0xDB);

   gc_transmit_timer = TRANSMIT_TIMER_TICKS;

   while(1)
   {
      getVoltage();
      transmitData();
   }
}

//--------------------------------------------------------
void getVoltage(void)      //reading 10-bit data from ADC(Voltage 0-300V)
{
result=0;
set_adc_channel(0);
delay_ms(1);
result=read_adc();
}

//---------------------------------------------------------
void transmitData(void)
{
   if(gc_transmit_timer)                   //refresh rate.
         return;
   else
     gc_transmit_timer = TRANSMIT_TIMER_TICKS;

   spi_write16(result);                  //sending data every 400ms.
   //spi_write16(1023);                     //for testing.

   

}


void spi_write16(int16 data)                //sending 10-bit data in two parts.
{
spi_write(make8(data, 1));   // Send MSB
spi_write(make8(data, 0));   // Send LSB
}


slave

Code:

//slave.c
#include <16f72.h>
#device *=8
#fuses HS,NOWDT,PUT,BROWNOUT,NOPROTECT
#use delay(clock=4000000)

void display(void);
void HTO7S(unsigned int16 Num);

#define  TICKS_BETWEEN_INTERRUPTS      5000 //5000      4/4=1   =1ms
#define  INTERRUPT_OVERHEAD            35   //cycles wasted
#define  TMR1RESET (0xFFFF-(TICKS_BETWEEN_INTERRUPTS-INTERRUPT_OVERHEAD))

#byte port_b=6 /* define the location of register port_b */
#byte port_c=7 /* define the location of register port_c */

byte CONST LED_MAP[11] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xFF};

//                          0    1    2    3    4    5    6    7    8    9   OFF

void spi_read16(void);
byte cnt=0,value,i;

byte Column[4]   = {0x80,0x40,0x02,0x10};         //Low bits(right,center,left)
byte Segment[4] = {0x12,0xE3,0xAB,0xAF};      

int16 res,data=0;
int8 x,y;

//--------------------------------------------------------
#INT_TIMER1
void Timer1(void)
{   
   set_timer1(TMR1RESET);
   display();   
   
}   


void main()
{
   set_tris_b(0); //1 set port_b as outputs
    set_tris_c(0);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);      //no division
   set_timer1(TMR1RESET);            //65535-4965=60570
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);
   setup_spi(SPI_SLAVE | SPI_H_TO_L | spi_ss_disabled  );
   enable_interrupts(INT_SSP);
   
   while(1)
     {
     /*   while(!spi_data_is_in()) ;
       
          data=spi_read();
   while(!spi_data_is_in()) ;
         data1=spi_read();
      x=make16(data,data1);
   */      
   
     HTO7S(data);
}
}

//-------------------------------------------------------
void display()
{
   
if(cnt>=4){
cnt=0;}
port_b=Segment[cnt];
//port_b=data;
port_c=Column[cnt];
//port_c=0xFF;
cnt++;
   
}

//--------------------------------------
// Convet HEX 2 byte to 7-Segment code
//--------------------------------------
void HTO7S(unsigned int16 Num)
{
   unsigned int16 res;                     //500ms interrupt to control display

   Segment[0]=LED_MAP[30*Num/10230];      //calculating look-up value from LED_MAP array.
   if (Segment[0]==0x40)                //turning off 1st digit if 0
   Segment[0]=0xFF;                  //dividing the three digits

   res = 30*Num%10230;
   Segment[1]=LED_MAP[10*res/10230];
   
   res=10*res%10230;
   Segment[2]=LED_MAP[10*res/10230];

   res=10*res%10230;
   Segment[3]=LED_MAP[10*res/10230];
}   

#INT_SSP
void ssp_isr(void)
{
spi_read16();
}

void spi_read16(void)     //reading both LSB and MSB from Master
{
   x=spi_read();
   y=spi_read();
   data=make16(x,y);            //making 16-bit data again.
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Jul 15, 2010 5:01 am     Reply with quote

Your big problem is _time_.
You are sending the two bytes one after the other.
Now the transmission takes just 2uSec to complete. There is no time for the slave to realise that the first byte has arrived, get into the interrupt, and retrieve it, before the second byte arrives.
It takes typically a minimum of about 30 instruction times to get into an interrupt. However the 'worst case' here will be if the chip has just decided to go into the timer interrupt, at the moment the data arrives. The two array retrievals, will each take perhaps 30uSec, add the time to increment the counter, set the RTCC register etc., and this will take perhaps 150uSec. Then another 30uSec to get into the RTCC interrupt.
There is only one character of buffering on the SPI. As soon as the second byte completes it transfers to the buffer register, and overwrites the earlier byte.
You need to allow time between sending the first, and second byte. Perhaps 150uSec.

Separately, there is the issue of sync. There is nothing in the code to ensure that the slave is expecting the bytes when the master sends them. It could easily see a spurious clock edge as the chip wakes up, and be clocking at the wrong point. This is where the 'Slave select' line comes in. Without this, you need to design a strategy to recover. Have the slave verify it is in the gap between characters before enabling the SSP (look for the clock line being high, and staying high). Add a pair of 'marker' bits at the top of the word (say '11' together in the top two bits). If this is not present in the received data stop the SSP, and synchronise again. Using SPI, without a select line, is not a good idea....

Best Wishes
bharatwalia



Joined: 04 May 2009
Posts: 35
Location: India

View user's profile Send private message

PostPosted: Sat Jul 17, 2010 8:29 am     Reply with quote

Hey thanks.

At last I solved the problem.
Its all about right timing and interrupt.

Thanks a lot... Very Happy
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