SPI - COMMUNICATION - MC68HC908QB8

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SPI - COMMUNICATION - MC68HC908QB8

3,279 Views
Opal
Contributor I
Hi Everyone,

I am using Controller MC68HC908QB8.
I am using 2 controllers one as master and another as slave.I am sending command from master to slave and accourding to that data slave has to process and send the data back to master. I am using master  to send command  and receive the data back .  Slave will start transmission only when master initiates the transmission but master has to initiate only after the process in the slave have finished.How can I achive this.
I used 2 concepts delay accourding to the proccess time taken in slave used delay in master and another one is from master I will send data continuosly and get the same data once the process is over I will send one data after that whatever data comes it will take the data as output. But the problem is it losed the sequence after 6 th value.

I am not able to trace why it happened so Pls could any one help me.

Thanks
 
Added p/n to subject.


Message Edited by NLFSJ on 2007-12-28 12:41 PM
Labels (1)
0 Kudos
9 Replies

698 Views
bigmac
Specialist III
Hello,
 
Possible alternative methods to that of simply providing a time delay within the master -
  1. Use a separate handshake output from the slave end, which can be asserted whenever new data is ready.  Of course, this requires an additional pin for each device.
  2. Provide handshaking within the SPI protocol, where the first byte value returned by the slave determines whether new data is available with subsequent transfer(s).
  3. Operate with dual masters.  Each end would normally operate as a slave, but would become a master only when it had data to send.
For methods 2 and 3, it would be usual to utilize the SPI interrupt for slave operation.  Interrupt is rarely necessary for master operation.
 
I assume that method 2 might be similar to one of the methods you have tried.  It is not possible to suggest a solution to your current problem without further details of the code you are using for master and slave ends, the data sequence used, and exactly how the problem is evidenced.
 
Regards,
Mac
 
0 Kudos

698 Views
Opal
Contributor I
Code:
//Master code //SCI used for only checking the data#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */#include <string.h>void sendSPI(unsigned int);void sendSCIvalue(unsigned int);void sendSCIchar(char);#define NAME  0x0Cint dummy = 0xEE;void main(void) {//int i;                       //Set Oscillator frequency  OSCSC  = 0x20;          // Set bus speed to 12.8 MHZ   OSCTRIM = Optional;     // this macro loads value at $FFC0 and store it in $0038.                        // bus clock speed is 3.2MHz +- 5%                        // Set up configuration registers     CONFIG2 = 0x05;     // Enable reset and IRQ pins    CONFIG1 = 0x01;     // disable the watch dog.  DDRA = 0x03;  DDRB = 0x40;  PTAPUE_PTAPUE2=1;   //enable pullup resistor on PTA2 // Configure ADC   ADCLK = 0x14;       // ADC 10 bit    ADSCR = 0x23;       // continuous conversion, channel 3 (PTA5)   // Configure ESCI   SCPSC = 0b10000111; //Baudrate = ((12.8Mhz/4) / (64*1*1*5.21875)) = 9580   SCC1  = 0x40;    SCC2  = 0x08;  // Configure SPI    SPSCR = 0x03;                                    SPCR_SPE = 1;  SPCR_SPMSTR = 1;  SPCR_CPHA = 1;//  SPCR_SPRIE = 1;  while(1){  sendSPI(NAME); }  }void sendSPI(unsigned int data)  {    unsigned int rec_data;    int x;       sendSCIvalue(data);       SPDR = data;       while(!SPSCR_SPRF);           x = SPSCR;       rec_data = SPDR;              sendSCIvalue(rec_data);         sendSCIchar(0x20);                     while(!(rec_data == 0x55))        {        SPDR = 0xFF;        while(!SPSCR_SPRF);            x = SPSCR;        rec_data = SPDR;        //sendSCIvalue(rec_data);        //sendSCIchar(0x20);              }              sendSCIvalue(rec_data);       //sendSCIchar(0x20);               SPDR = dummy;        while(!SPSCR_SPRF);          x = SPSCR;        rec_data = SPDR;        sendSCIvalue(rec_data);        sendSCIchar(0x20);                SPDR = dummy;        while(!SPSCR_SPRF);          x = SPSCR;        rec_data = SPDR;        sendSCIvalue(rec_data);        sendSCIchar(0x20);        sendSCIchar(0x0D);        sendSCIchar(0x0A);} void sendSCIvalue(unsigned int hex) { int temp4,temp3,temp2,temp1,temp0,temp,tem,te; char dec;  temp4 = hex/0x2710; dec = ((temp4 & 0xf) | 0x30); sendSCIchar(dec);  te = hex % 0x2710;      temp3 = te / 0x3E8; dec =  ((temp3 & 0xf) | 0x30);                                  //(char *) ((temp3<12) & 0xF000)|0x30;; sendSCIchar(dec);  temp2 = te % 0x3E8;  temp1 = temp2 / 0x64; dec =  ((temp1 & 0xf) | 0x30); sendSCIchar(dec);  temp = temp2 % 0x64;  temp0 = temp/0xA; dec  = ((temp0 & 0xf) | 0x30); sendSCIchar(dec); tem = temp % 0xA;     dec  = ((tem & 0xf) | 0x30); sendSCIchar(dec);}void sendSCIchar(char i){  unsigned char u8serialCount;  u8serialCount=SCS1;  SCDR = i;  while(!SCS1_TC);}

Code:
//Slave code//SCI used for data verification#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */void init_ports(void);void commandselection(int);void sendSPIdata(unsigned int);void sendSCIvalue(unsigned int);void sendSCIchar(char);void getthreshold (void);unsigned int eread(int);void sendSPIvalue(unsigned int);#define ELECTRODE 1unsigned int thres_value[4];unsigned int thres_setvalue[4];void main(void) {  int temp,rec_data; init_ports(); SPDR = 0X01;   while(1)    {     //SPDR = 0X01;     while(!SPSCR_SPRF);     temp = SPSCR;        //To clear the bit      rec_data = SPDR;            EnableInterrupts;     //Master is sending data continuously        SPCR_SPRIE = 1;       //To clear SPSCR_SPRF bit Interrupt routine is used                    sendSCIvalue(rec_data);     sendSCIchar(0x20);          if(rec_data == 0x0C)       commandselection(rec_data);          }}/**************************************************************************************************///Port initialization/**************************************************************************************************/void init_ports() {     //Set Oscillator frequency  OSCSC  = 0x20;          // Set bus speed to 12.8 MHZ   OSCTRIM = Optional;     // this macro loads value at $FFC0 and store it in $0038.                        // bus clock speed is 3.2MHz +- 5%                        // Set up configuration registers     CONFIG2 = 0x05;     // Enable reset and IRQ pins    CONFIG1 = 0x01;     // disable the watch dog.  DDRA = 0x03;  DDRB = 0x40;  PTAPUE_PTAPUE2=1;   //enable pullup resistor on PTA2 // Configure ADC   ADCLK = 0x14;       // ADC 10 bit    ADSCR = 0x23;       // continuous conversion, channel 3 (PTA5)   // Configure ESCI   SCPSC = 0b10000111; //Baudrate = ((12.8Mhz/4) / (64*1*1*5.21875)) = 9580   SCC1  = 0x40;    SCC2  = 0x08;  // Configure SPI    SPSCR = 0x03;       //Baud rate                             SPCR_SPE = 1;       //Enabiling SPI   SPCR_SPMSTR = 0;    //Enabling slave  SPCR_CPHA = 1;        SPCR_SPRIE = 0;     //Interrupt reciver  }void commandselection(int command) {   // int l,m;     switch(command) {    case 0x0C:               //sendSCIvalue(command);     //sendSCIchar(0x20);     //getthreshold();           //     To read the proximity elevtrode values          sendSPIdata(0x22CC);        //   For checking purpose  using this data     SPDR = 0xAA;        break;        default :    break;    }       //sendSCIvalue(command);   //sendSCIchar(0x20);   }void getthreshold (){ int ch;  for(ch=1;ch<=ELECTRODE;ch++)   {        thres_value[ch-1] = eread(ch);    sendSPIdata(thres_value[ch-1]);     //send data to this function to send thru SPI      }   sendSCIchar(0x0A);   sendSCIchar(0x0D);    }/**************************************************************************************************/  //Read values of electrode/**************************************************************************************************/unsigned int eread(int ch) {  unsigned int evalue;      PTA = PTA & 0xFC;                //PortA 0 & 1 & port B to select electrode from 1 to 7  PTA = PTA | (ch & 0x03);    ch = ch << 4;    PTB = PTB & 0xBF;  PTB = PTB | (ch & 0x40);    while(!(ADSCR & 0x80));    //wait until conversion completes  evalue = ADR;  return(evalue);  }/******************************************************************************************/ // //Interrupt Routine for reciving thru SPI // ///******************************************************************************************/void interrupt 13 ISR_SPI() {int temp=0,rec_data=0;temp = SPSCR;        //To clear the bit rec_data = SPDR;}    /**************************************************************************************************///Spliting of bytes and sending byte by byte/**************************************************************************************************/  void sendSPIdata(unsigned int hex) {  int temp1,temp2,temp,rec_data;  //char dec;    temp1 = hex/100;            //to split data byte by byte  temp2 = hex%100;    DisableInterrupts;  SPCR_SPRIE = 0;    while(!SPSCR_SPRF);     temp = SPSCR;             rec_data = SPDR;   sendSPIvalue(0x55);        //say to Master the data coming here after is the data it has to get  sendSPIvalue(temp1);  sendSPIvalue(temp2);    }/**************************************************************************************************///Transmit data through SCI only for testing/**************************************************************************************************/void sendSPIvalue(unsigned int i){  int temp,rec_data;     SPDR = i ;  while(!SPSCR_SPRF);  temp = SPSCR;        //To clear the bit   rec_data = SPDR;      sendSCIchar(0x20);  sendSCIvalue(rec_data);   }void sendSCIvalue(unsigned int hex) { int temp4,temp3,temp2,temp1,temp0,temp,tem,te; char dec; //int divideratio[3] = {0x2710,0x3E8,0x64,0xA}  temp4 = hex/0x2710; dec = ((temp4 & 0xf) | 0x30); sendSCIchar(dec);  te = hex % 0x2710;      temp3 = te / 0x3E8; dec =  ((temp3 & 0xf) | 0x30);                                  //(char *) ((temp3<12) & 0xF000)|0x30;; sendSCIchar(dec);  temp2 = te % 0x3E8;  temp1 = temp2 / 0x64; dec =  ((temp1 & 0xf) | 0x30); sendSCIchar(dec);  temp = temp2 % 0x64;  temp0 = temp/0xA; dec  = ((temp0 & 0xf) | 0x30); sendSCIchar(dec); tem = temp % 0xA;     dec  = ((tem & 0xf) | 0x30); sendSCIchar(dec);}void sendSCIchar(char i){  unsigned char u8serialCount;  u8serialCount=SCS1;  SCDR = i;  while(!SCS1_TC);}

 
 Hello bigmac,

These are the codes I have used to send data from master and slave.

In 3rd concept  first master is sending command after that I am making it slave.so it will have to do in continuous loop say for eg while(1); til the second master is sending data once 2nd master  sends the data
Again first master has to send data  if it is continuous mode ie while(1) till an interrupts occur how to make it again as master to send data/

Thanks
0 Kudos

698 Views
bigmac
Specialist III
Hello,
 
I see some potential problems with your slave code.  You are clearing the SPI receive flag within the ISR, but are then reading and writing to SPDR within main and other functions.  To maintain synchronism, I would suggest that the reading and writing also needs to be done within the ISR, with possibly the following sequence -
  1. Clear SPRF flag (read SPSCR)
  2. Read SPDR, test for command value, and place in global variable, if required.
  3. Test for data value to be returned (possibly by means of a global flag)
  4. If so, write return value to SPDR, else write "no data" value to SPDR
The data value will be returned when the master initiates the next transfer.  All other processing should be done from outside the ISR, using the global variables to communicate with the ISR.
 
I presume that you have the SS pin tied permanently low at the slave.  This could be problematic with the presence of any spurious clock pulses (perhaps caused by noise).  IMHO it is better to frame the sequence by the master returning SS high after each transfer.  With CPHA = 1, this could be done after the transfer of a number of bytes.  However, with CPHA = 0, it must be done after the transfer of every byte.
 
I notice that you have set the master for the slowest SPI clock rate.  Usual practice is to use the fastest clock rate available, that is compatible with the slave device.  However, I also notice that you are sending a continuous data stream from the master, by virtue of the while loop.  A better arrangement would be to pace the sending of data for a rate comparable with the slave command processing time, perhaps using the TIM module within the master.  For the present code, the pacing is determined by the slow SPI clock rate.
 
Primarily within your code for the master, you have a separate line that reads SPSCR.  This line is unnecessary since it alway occurs after the SPRF flag (within the same register) has been tested.  When I use the SPI module, I would usually test for the SPTEF flag being set before writing to the SPDR register.  While not always necessary, particularly for the HC908 SPI,  it can avoid potential problems when using other 9S08 devices.
 
A final observation is your widespread use of 16-bit variables.  With an 8-bit MCU, more efficient code will result if you declare 8-bit variables, preferably unsigned, unless it is absolutely necessary to use larger ones.  Since 8-bit values are always used for peripherals such as the SPI and SCI, it makes no sense to use 16-bit values in these instances.
 
Regards,
Mac
 
0 Kudos

698 Views
Opal
Contributor I
Hello ,

Thank you.
I have written a program only to communicate between master and slave. Master has to send data continuosly but slave will place a data only after a delay. If slave didnt place any data in Data register then master will receive whatever data in the slave shift register.
Code:
//Master code#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */void sendSCIvalue(unsigned int);void sendSCIchar(char);void main(void) {  EnableInterrupts; //Set Oscillator frequency  OSCSC  = 0x20;          // Set bus speed to 12.8 MHZ   OSCTRIM = Optional;     // this macro loads value at $FFC0 and store it in $0038.                        // bus clock speed is 3.2MHz +- 5%                        // Set up configuration registers     CONFIG2 = 0x05;     // Enable reset and IRQ pins    CONFIG1 = 0x01;     // disable the watch dog.  DDRA = 0x03;  DDRB = 0x40;  PTAPUE_PTAPUE2=1;   //enable pullup resistor on PTA2 // Configure ADC   ADCLK = 0x14;       // ADC 10 bit    ADSCR = 0x23;       // continuous conversion, channel 3 (PTA5)   // Configure ESCI   SCPSC = 0b10000111; //Baudrate = ((12.8Mhz/4) / (64*1*1*5.21875)) = 9580   SCC1  = 0x40;    SCC2  = 0x08;  // Configure SPI    SPSCR_SPR1 = 0;  SPSCR_SPR0 = 0;                                      SPCR_SPE = 1;  SPCR_SPMSTR = 1;  SPCR_CPHA = 1;  SPCR_SPRIE = 1;    SPDR = 0xFF;  while(1);  }/******************************************************************************************/ // //Interrupt Routine for reciving thru SPI // ///******************************************************************************************/void interrupt 13 ISR_SPI() {int temp=0,rec_data=0;temp = SPSCR;        //To clear the bit rec_data = SPDR;sendSCIvalue(rec_data);sendSCIchar(0x20);SPDR = 0xFF;}

 
Code for slave
Code:
#include <hidef.h> /* for EnableInterrupts macro */#include "derivative.h" /* include peripheral declarations */void sendSCIvalue(unsigned int);void sendSCIchar(char);void delay(void);int k=0 ;void main(void) {  EnableInterrupts;  //Set Oscillator frequency  OSCSC  = 0x20;          // Set bus speed to 12.8 MHZ   OSCTRIM = Optional;     // this macro loads value at $FFC0 and store it in $0038.                        // bus clock speed is 3.2MHz +- 5%                        // Set up configuration registers     CONFIG2 = 0x05;     // Enable reset and IRQ pins    CONFIG1 = 0x01;     // disable the watch dog.  DDRA = 0x03;  DDRB = 0x40;  PTAPUE_PTAPUE2=1;   //enable pullup resistor on PTA2 // Configure ADC   ADCLK = 0x14;       // ADC 10 bit    ADSCR = 0x23;       // continuous conversion, channel 3 (PTA5)   // Configure ESCI   SCPSC = 0b10000111; //Baudrate = ((12.8Mhz/4) / (64*1*1*5.21875)) = 9580   SCC1  = 0x40;    SCC2  = 0x08;  // Configure SPI    SPSCR_SPR1 = 0;  SPSCR_SPR0 = 0;                                      SPCR_SPE = 1;  SPCR_SPMSTR = 0;  SPCR_CPHA = 1;  SPCR_SPRIE = 1;      SPDR = 0xAA;  while(1);}/******************************************************************************************/ // //Interrupt Routine for reciving thru SPI // ///******************************************************************************************/void interrupt 13 ISR_SPI() {int temp=0,rec_data=0;temp = SPSCR;        //To clear the bit rec_data = SPDR;sendSCIvalue(rec_data);SPDR = 0xAA;sendSCIchar(0x20);if(k == 0) {    k = 1;     delay();    sendSCIchar(0x20);    }}void delay() {int i;for(i=0; i<100 ;i++);SPDR = 0xAA; k = 0;}

 There is no connection for SS pin in both slave and master. In slave part I am getting 255 as output and after some time there is no output in hyper terminal. In master part I am getting 170 and sometimes 255 but after some time only getting 0 contniously. Kindly help me to trace why it is happening so.

Thanks

0 Kudos

698 Views
Opal
Contributor I
Sorry !

In slave code , In reciver  Interrupt routine this line should not be there  //SPDR = 0xAA .

Once again sorry for inconvenience.

Thanks!
0 Kudos

698 Views
PeterHouse
Contributor I
Just a couple of notes on what I see.

1. I would recommend getting the SCI send OUT of the interrupt.  Interrupts should be very short and I don't know if your SCI routine blocks until the character is sent or not but serial communication at 9600 baud takes each byte 1ms where an SPIbyte can be sent in 10us or less.  Store the byte and set a flag in the interrupt and check the flag in main to send the byte and clear the flag.

2. The SS line or some type of CS or Chip Select is usefull for "packetizing" your data to break up your data stream.  I have used this approach often between coprocessors.

If you will contact me off list, I will send you some code I have for a project which swaps 9 bytes between two processors using SPI.  You could probably edrop it in and use it.  It was written for an 'S08GB60

Peter
peter.house@centricsystems.com
0 Kudos

698 Views
Opal
Contributor I
Hi,

I understand  first point But without using SCI how can I know whether data is coming
correct or not. Both in master and slave side.

If I use SCI in slave side alone to display the data from the master,then I am getting the output
contniously.

If I use SCI in both master and slave then I am not getting data contniously in both side.

If I use SCI in master alone then also I am not getting output contniously It stops after 2 secs.

Slave code is:
TMOD = 0xFFFF;
TSC = 0X42; //Internal frequency %4
void interrupt 13 ISR_SPI() {

int temp=0;
char rec_data=0;

temp = SPSCR;        //To clear the bit
rec_data = SPDR;
  if( flag == 1) {
   SPDR = name;
   //sendSCIchar(rec_data);
 
   flag = 0;
}
}

//Timer Interrupt

interrupt 6  void TIM_ISR(void)


    TSC_TOF = 0;
    flag++;
    //sendSCIvalue(0x01);
}

Master code:
void interrupt 13 ISR_SPI() {

int temp=0;
char rec_data=0;

temp = SPSCR;        //To clear the bit
rec_data = SPDR;

//sendSCIvalue(rec_data);
sendSCIchar(rec_data);
 SPDR = name;
}


Could you send that code also pls.

Thanks

0 Kudos

698 Views
PeterHouse
Contributor I
I am not suggesting you not use the SCI.  I am suggesting in the interrupt routine you store the received data and set a flag.  In you main loop you should check the flag and if it is set then clear it and send the byte using the SCI.  This keeps your interrupt routine very short and your main loop can "spin" while the SCI transmits the byte.
 
Here is some pseudo code for the main loop:
char Byte_2_Send
char Byte_2_Send_Flag
#define TRUE 1
#define FALSE 0
 
{
// Check to see if SCI is busy transmitting
if ( SCI_Busy )
// Busy - Do Nothing
 
else
// Not Busy - Check to See if Data is Ready to Send
 
   // Check to See if Data is Ready to Send
   if ( Byte_2_Send_flag == TRUE )
   // Data is Ready - Send it
 
      SCI_Data_Register = Byte_2_Send
      Byte_2_Send_Flag = FALSE
 
   else
   // Data is Not Ready - Do Nothing
   end if
end if
}
 
Here is some pseudo code for the Intterupt:
{
  
   Byte_2_Send = SPIDR
   Byte_2_Send_Flag = TRUE

   // Don't forget to clear Interrupts and other housekeeping
}
 
 
Good Luck,
 
Peter
0 Kudos

698 Views
Opal
Contributor I
Hello,
 
I have done one simple program in SPI .
From master sending one char contniously ,If reciver flag is set then after clearing the flag send the recived value to SCI. In slave , only clearing  the SPI reciver flag. Since In SPI when master start transmitting it will also start receving what ever data in the slave shift register at that time. So  from the second data of transfer from master. Master is expected to receive whatever data that send to slave previously.
 
Master Code:
while(1)
{
SPDR = name;
  while(!SPSCR_SPRF);  
    rec_data = SPDR;
   sendSCIchar(rec_data);
}
Slave code:
while(1)
 {
  
  while(!SPSCR_SPRF);  
       rec_data = SPDR;
}
 
When name =  'A'  Not getting A all the times.
When name =  'B'  Getting B contniouly.
When sending  two data in the while loop that is when sending A and B from master.
Getting AB contniously.
when name = 'C' Getting different characters in the middle.
when name = 'D' Getting D contniously.
 
when SPDR = 0xAA getting contniously.
when SPDR = 0xAB getting different character in the middle.
 
My assumption is when the characters equivalent binary ends with (LSB) 1 I am getting this problem.
I didnt understand why it is behaving differently still problem with my Code. Or problem with my circuit.
Or whether my understaning of SPI is not correct.
 
Kindly Help to solve this problem.
 
 
 
 
 
 
 
0 Kudos