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 help

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



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

spi help
PostPosted: Wed Nov 11, 2009 3:55 pm     Reply with quote

Ok so what I have done in my project is a wireless intercom using GSM. Its interfaced with a LCD and a touchpad (capacitive touch 16F727)... GSM part working sweet. Now wanna prompt the modem from user interface module via SPI. Once send, the slave jumps into its ISR. But SSPBUF got nothing inside. I will try summarise the code as best.

Compiler : 4.084
Code:

//MASTER DEVICE AND CONTROLLER OF USER INTERFACE
#include <16F727.h>
#device adc=8

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//*****************************************************************************
// The following initializes the first 4 locations of the data EERPOM
//  using the #ROM directive. following for EEPROM
#rom 0x2100={1,2,3,4}
typedef int8 INTEE;           //internal eeprom is 8bit wide

unsigned int8 address;

//*****************************************************************************
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                    //Internal RC Osc
#FUSES NOPUT                    //No Power Up Timer
#FUSES MCLR                     //Master Clear pin enabled
#FUSES NOPROTECT                //Code not protected from reading                 
#FUSES NODEBUG                  //No Debug mode for ICD
               
#use delay(clock=8000000)

//*****************************************************************************
#define LCD_ENABLE_PIN PIN_B0
#define LCD_RS_PIN PIN_B1
#define LCD_RW_PIN PIN_B2
#define LCD_DATA_PORT B
#define LCD_TYPE 2
#include <NEW lcd.c>          //calls a seperate c file that assists printing on screen.

int8 SPI(int *c);
int8 result;
#define SPI_SS   PIN_A5             //Slave select here connects to pin A5 of PIC18F4620 aswell.


// SPI mode definitions.
#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)


// SPI commands accepted by the SPI Slave PIC.
// The slave will respond to each of these commands
// with a single byte.   These must be the same
// values as defined in the Slave source code.

#define READ_CALLING1             30     //is it dialing...
#define READ_CALLING2             2
#define READ_CALLING3             3
#define READ_TERMINATE_CALL       4     //read security pin for manually toggling gate
#define READ_CALLING11            5
#define READ_CALLING12            6
#define READ_CALLING13            7
#define READ_CALLING21            8
#define READ_CALLING22            9
#define READ_CALLING23            10
#define READ_CALLING31            11
#define READ_CALLING32            12
#define READ_CALLING33            13

//======================================


void main()
{

   output_high(SPI_SS);           // Initial Slave Select to a high level
   setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4);
  spi(1);

}


//*****************************************************************************
//SETUP SPI
//*****************************************************************************
int8 SPI(int *c)
{
   //switch between diff commands, ie calling house 1,2 or 3. end call... etc   
   switch(c)
    {

     case 1:                    // Read if calling on Slave PIC
      lcd_putc("\f     INSIDE!     ");
       output_low(SPI_SS);
       spi_write(30); // Send command to slave
      //SSPBUF = 30;
       output_high(SPI_SS);

       delay_us(500);           //some arb value for now, will be to display when -> "calling"

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);

       if(result==60)
       {
          lcd_putc("\f     REPLIES!     ");
       }   
       break;
       
/***************************************************************************************/
      case 2:                    // Read if calling on Slave PIC
       output_low(SPI_SS);
       spi_write(READ_CALLING2 ); // Send command to slave
       output_high(SPI_SS);

       delay_us(500);             //some arb value for now, will be to display when -> "calling"

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);
   
       break;
/***************************************************************************************/       
      case 3:                    // Read if calling on Slave PIC
       output_low(SPI_SS);
       spi_write(READ_CALLING3 ); // Send command to slave
       output_high(SPI_SS);

       delay_us(500);             //some arb value for now, will be to display when -> "calling"

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);
   
       break;
/***************************************************************************************/       
     case 4:                 // Read security pin on Slave PIC then maybe store in EEPROM
       output_low(SPI_SS);
       spi_write(READ_TERMINATE_CALL); // Send command to slave
       output_high(SPI_SS);

       delay_us(300);

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);
   
       break;
 
     
     default : break;
       
     
    }

}





SLAVE:

Code:
//SLAVE DEVICE + CONTROLLER OF GSM MODULE
#include <18F4620.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// The following initializes the first 3 locations of the data EERPOM
//  using the #ROM directive. following for EEPROM
#rom int 0xf00000={1,2,3,4}
typedef int8 INTEE;           //internal eeprom is 8bit wide

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                    //Internal RC Osc
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOPUT                    //No Power Up Timer
//#FUSES MCLR                   //Master Clear pin enabled
#FUSES NOLVP

#use delay(clock=8000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8, stop=1)
#byte RCSTA = 0xFAB
#byte SSPBUF = 0xFC9  // Register address for 18F4620, Synchronous Serial Port Receive Buffer/Transmit Register
#byte TRISD = 0xF95
#byte PORTD = 0xF83
#byte RCSTA    = 0xFAB
//*************DTMF port setup             
#byte PORTB    = 0xF81
#byte TRISB = 0xF93
#byte TRISD = 0xF95
#byte TRISC = 0xF94

// This program demonstrates an SPI slave that can
// be read by the master.   Three different types
// of data (single bytes only) are returned upon
// command by the master.

// SPI modes for setup_spi() function.
#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)


// SPI commands accepted by this slave program.
// These must be non-zero values.
#define READ_CALLING1      1     //is it dialing...
#define READ_CALLING2      2
#define READ_CALLING3      3
#define READ_PIN           4     //read security pin for manually toggling gate
#define READ_POWERUPQ      5     //read if modem powered up and ready
#define READ_SIM           6
#define test               20

void main()
{
   
   SET_TRIS_B( 0x1F );               //set B0-B4 inputs; to poll the DTMF decoder, MAYBE ONLY ONCE CALL INITIATED....
   
   setup_spi(SPI_SLAVE | SPI_MODE_3);
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);         


SSPBUF = 0;

   clear_interrupt(INT_SSP);
   enable_interrupts(INT_SSP);

enable_interrupts(global);
//TRISC_MSCL=1;
//TRISC_MSDI=1;
TRISC_MSDO=0;

while(1);

#int_ssp
void ssp_isr(void)
{
delay_ms(100);
   command = SSPBUF;
   output_high(pin_D1);
   SSPBUF = 40;
  //spi_write(40);
   switch(command)                  // Act on it
  {

//************************************//
     //case READ_CALLING1:      //this will go and check if ringing or not
     case 30:
   //output_high(pin_D1);
     //if (SendCommandGetOK()){
     //do something to check if dialing
     //}
    //make_call();
    //output_high(pin_D1);
     SSPBUF = CALLING_VALUE1;        //PUT BACK INTO REG FOR MASTER TO THEN ACCEPT BACK
     break;
//************************************//
     case READ_CALLING2:      //this will go and check if ringing or not
     
     //if (SendCommandGetOK()){
     //do something to check if dialing
     //}
     SSPBUF = CALLING_VALUE2;     
     break;
//************************************//
     case READ_CALLING3:      //this will go and check if ringing or not
     
     //if (SendCommandGetOK()){
     //do something to check if dialing
     //}
     SSPBUF = CALLING_VALUE3;        //PUT BACK INTO REG FOR MASTER TO THEN ACCEPT BACK
     break;
//************************************//
     case READ_PIN:
     
     //if (SendCommandGetOK()){
     //maybe not needed here
     //}
     SSPBUF = PIN_VALUE;      //return PIN number if owner enters it via sms, maybe store into EEPROM of master device on boot.
     break;
//************************************//
     case READ_POWERUPQ:
     SSPBUF = POWERUPQ_VALUE;      //returns number 5 if powered up.
     break;
//************************************//     
     case READ_SIM:
     
     //if (SendCommandGetOK(CREGQUERY)){
     //do something to check if 2,1 ie connected to home network
     //}
     SSPBUF = SIM_VALUE;      //this will go and check SIM status/antenna strength and return it to master device to display on screen
     break;
     
     //************************************//
     case test:
     //SSPBUF = test_val;      //returns number 5 if powered up.
     //output_high(pin_D1);
   
     break;
  }

}
davidroux



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

PostPosted: Wed Nov 11, 2009 3:57 pm     Reply with quote

and yes there is a good chance this wont compile.. my main code is 2500 lines... and yes i was modding it like mad since this morning... tried to base from this -> http://www.ccsinfo.com/forum/viewtopic.php?t=39145&highlight=ssp

gonna re write neat tomorrow and update this.. if there arent any noticeable errors u guys pick up... u can also see i was trying to do write to bits.. ie using #bit.. where u prob wont need using the SPI function CCS offers..
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Nov 11, 2009 4:05 pm     Reply with quote

Quote:

int8 SPI(int *c);


void main()
{

output_high(SPI_SS); // Initial Slave Select to a high level
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4);
spi(1);
}


//*********************************************
//SETUP SPI
//*********************************************
int8 SPI(int *c)
{
//switch between diff commands, ie calling house 1,2 or 3. end call... etc
switch(c)
{

Why do you declare the SPI() as taking a pointer to a integer, and
then you give it the number '1' ?

It's clear to me that SPI should just be declared as taking an 'int' as
the input parameter, and not a pointer to an 'int'.

Also, why do you let the main() function fall off the end ?
Put a while(1); statement at the end of main() to prevent this.
ckielstra



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

View user's profile Send private message

PostPosted: Wed Nov 11, 2009 6:42 pm     Reply with quote

Configure the same SPI mode in both the Master and Slave (you have mode 0 and 3).
davidroux



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

thnanks
PostPosted: Wed Nov 11, 2009 11:38 pm     Reply with quote

thanks guys.. yeah i really hacked my code hahah trying different modes (when my ICD 2 decided to fall apart hehe)... and left out while(1) trying to add as little code as possible.. gonna sort it out today and update.. thanks a ton ppl! Smile
davidroux



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

PostPosted: Thu Nov 12, 2009 6:54 am     Reply with quote

ok so here is my little test app... i run both off debuggers so can see what packets sending... pickit 2 running the slave (PIC18F462) and master running on icd2(PIC16F727)..

i get an interrupt when master sends, slave jumps into isr but with command = 0!!! so switch is pointless for now... any ideas? oh and tried changing to different modes and turning up and down -> SPI_CLK_DIV_64 and SPI_CLK_DIV_4

Master :

Code:
//Master   Slave
//SCLK --> SCLK
//SDO  --> SDI
//SDI  <-- SDO
//\CS  --> \SS
//GND <--> GND

// This program demonstrates an SPI Master that can
// read bytes from a SPI slave. (Single bytes only).

#include <16F727.H>
#fuses INTRC_IO, NOWDT, NOPROTECT, PUT
#use delay(clock=4000000)

#define SPI_SS   PIN_A5
void spi_run(void);
// SPI mode definitions.
#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)


// SPI commands accepted by the SPI Slave PIC.
// The slave will respond to each of these commands
// with a single byte.   These must be the same
// values as defined in the Slave source code.
#define TEST1            1
#define TEST2          2
#define TEST3           3

int c;
int8 result;

//======================================
void main()
{
output_high(SPI_SS);  // Initial Slave Select to a high level

// Initialize the hardware SSP for SPI Master mode.
setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64);

delay_ms(5000);
c=1;
while(1)
{
spi_run();
}

}

// If the user presses a key on the PC, get the
// character, convert it to an SPI command byte,
// and send it to the slave.  Then get the response
// byte from the slave and display it.
void spi_run()
{
   switch(c)
    {
     case 1:     // Read ADC on Slave PIC
       output_low(SPI_SS);
       spi_write(1);  // Send command to slave
       output_high(SPI_SS);

       delay_us(100);  // Give slave some time to respond

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);
   
       break;

     case 2:     // Read switch on Slave PIC
       output_low(SPI_SS);
       spi_write(TEST2); // Send command to slave
       output_high(SPI_SS);

       delay_us(100);

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);
   
       break;


     case 3:     // Read counter on Slave PIC
       output_low(SPI_SS);
       spi_write(TEST3); // Send command to slave
       output_high(SPI_SS);

       delay_us(100);

       output_low(SPI_SS);
       result = spi_read(0);     // Read response from slave
       output_high(SPI_SS);

       break;

     
     default:
 
       break;
    }

}



SLAVE :

Code:
// This program demonstrates an SPI slave that can
// be read by the master.   Three different types
// of data (single bytes only) are returned upon
// command by the master.

#include <18F4620.H>
#device adc=8
#FUSES INTRC_IO                    //Internal RC Osc
#fuses NOWDT
#fuses NOPROTECT
#fuses BROWNOUT
#fuses NOPUT
#fuses NOLVP
#use delay(clock=4000000)

#byte SSPBUF = 0xFC9  // Register address for 16F877

// SPI modes for setup_spi() function.
#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)

// SPI commands accepted by this slave program.
// These must be non-zero values.
#define TEST1            1
#define TEST2          2
#define TEST3           3

int8 command;


//======================================
void main()
{

delay_us(20);

// Initialize the hardware SSP for SPI Slave mode 0.
setup_spi(SPI_SLAVE | SPI_MODE_0);

// Enable interrupts for the SPI slave.
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);

// Update ADC value every 100 ms.
while(1)
  {
    delay_ms(100);
  }

}


//----------------------------
// An int_ssp interrupt will occur whenever the SPI master
// transmits a byte to this slave PIC.   The following
// interrupt service routine (isr) decodes the command byte
// and sends back the appropriate response byte to the master.
// After sending the command byte with spi_write(), the master
// must call spi_read(0) to get the data byte.

#int_ssp
void ssp_isr(void)
{
int8 command;
command = SSPBUF;
//output_high(pin_D0);
switch(command)   // Act on it
  {
   case TEST1:
    output_high(pin_D0);
     SSPBUF = 10;         //some arb value to see if working from slave -> master
     break;

   case TEST2:
     SSPBUF = 20;         //some arb value to see if working from slave -> master   
     break;

   case TEST3:
     SSPBUF = 30;         //some arb value to see if working from slave -> master
     break;
  }

}

davidroux



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

PostPosted: Thu Nov 12, 2009 7:07 am     Reply with quote

hardware...-> running as stated... internal OSC

another thing.. if i go SSPBUF = 10; on slave.. it rights perfectly.. if i do the same on master... it stays at 0??? maybe the master is never writing anything??

summary : it gets into the receive ISR for SPI.... but sees 0x00 so does not go into any case's.... which makes no sense... as to how can it get an interrupt but not have anything in SSPBUF?
Ttelmah
Guest







PostPosted: Thu Nov 12, 2009 11:16 am     Reply with quote

When you put a byte into SSPBUF on the master, it will immediately be transferred to the output shift register, and start clocking out. SSPBUF will get refilled with whatever clocks back from the slave after the transfer, and the buffer full bit will set. On the slave, it'll stay in SSPBUF, till the master clocks it out, when it gets replaced with the byte from the master, and again the buffer full bit sets.
You can't actually read back the byte in the SSPBUF that you have written on a master, it is already 'in transit'....
It'll get into the ISR, whenever 8 clocks have been received. '0' is a perfectly legitimate value. You _will_ receive zero, since this is what you clock out, in order to read the data back on the master.
Are you sure you have your connections correct?.
SDO on the master to SDI on the slave, and vice-versa. SCK on master to SCK on slave (it looks like you have this, since otherwise the intrupt would not trigger). Pin A5 on master , to pin A5. You show all this on the header, but use symbolic names (SS for example). Have you triple checked it....
Have you also checked what chip revision you have, and looked at the errata. Especially for the 4620, which has several on the MSSP module. In particular there is one requiring a _delay_ between dropping SS, and starting to clock the data. On older revision chips there is one for a SPI slave, that requires adding a series resistor in the connection to SDI on the chip....

Best Wishes
davidroux



Joined: 19 Jul 2009
Posts: 11

View user's profile Send private message

PostPosted: Fri Nov 13, 2009 7:17 am     Reply with quote

ok guys really need help... i can get reply perfect from slave to master... still send 0x00 from master :( so never flashes LED (on D1)

LCD writes replies... which shows working from slave to master...

master : (beefy part only)

Code:
      lcd_putc("\f     INSIDE!     ");
//       output_low(SPI_SS);
//       delay_ms(10);
//       spi_write(0x5A); // Send command to slave
//      delay_ms(10);
//      output_high(SPI_SS);


output_low(SPI_SS);
   delay_ms(1);
   WRITE_SSP(5);
   //WAIT_FOR_SSP(); //Wait for the master to receive the byte sent
   delay_ms(1);
output_high(SPI_SS);
       delay_ms(500);           //some arb value for now, will be to display when -> "calling"

       output_low(SPI_SS);
       result = spi_read();     // Read response from slave
       output_high(SPI_SS);

       if(result==0xA5)
       {
          lcd_putc("\f     REPLIES!     ");
       }



Slave :

Code:
#include <18F4620.H>
#device adc=8
#FUSES INTRC_IO                   //Internal RC Osc
#fuses NOWDT
#fuses NOPROTECT
#fuses NOBROWNOUT
#fuses NOPUT
#fuses NOLVP
#use delay(clock=8000000)

// SPI modes for setup_spi() function.
#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)

#define SPI_SS   PIN_A5

#byte SSPCON1 = 0xFC6
#byte   SSPBUF = 0xFC9
#byte   SSPSTAT = 0xFC7
#byte TRISC = 0xF94
#byte TRISA = 0xF92

#bit MSCL = TRISC.3
#bit MSDI = TRISC.4
#bit MSDO = TRISC.5
#bit SS = TRISA.5

/* 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 crystal 8000000

int8 command;
INT8 c;
//======================================
void main()
{
SS=1;
MSCL=1;
MSDI=1;
MSDO=0;
// Initialize the hardware SSP for SPI Slave mode 0.
setup_spi(SPI_SLAVE | SPI_MODE_0);

// Enable interrupts for the SPI slave.

//clear_interrupt(INT_SSP);
//enable_interrupts(INT_SSP);
//enable_interrupts(GLOBAL);

delay_ms(1000);

  while(true){
   WAIT_FOR_SSP();
   c = READ_SSP();
   output_high(pin_D0);

   if (c==5)
   {
      output_high(pin_D1);
   }
   WRITE_SSP(0xA5);
   WAIT_FOR_SSP(); //Wait for the master to receive the byte sent
   output_high(pin_D2);
   c=READ_SSP(); //Clear the buffer here, so I can wait for the next byte

output_low(pin_D0);
output_low(pin_D2);
delay_ms(1000);
   }



}
ckielstra



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

View user's profile Send private message

PostPosted: Fri Nov 13, 2009 10:48 am     Reply with quote

What is the hardware revision of your PIC18F4620? Several different silicon revisions do exist for this chip, some having serious (but different) SPI problems.

Have you tried inserting a resistor between SDO of the master and SDI of the slave? This might help for some silicon revisions. I guess a value of 1k Ohm will do.

Post small and complete test programs. Your master program is incomplete so we can't check you have the right setup used. The slave code is way too large with lots of unused defines and variables.

A potential problem in your slave code is that you are expecting two bytes in a fixed sequence. But what will happen when the slave gets out of Sync? You will never detect the 0xA5 byte and it seems like the slave is not working.
For a first test make the slave program as simple as possible with only receiving a single byte.

You manually configure the TRIS bits. Beware that the compiler by default will manage the TRIS registers for you and can mess up these settings. Check out the manual for the directive '#use fast_io'.
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