|
|
View previous topic :: View next topic |
Author |
Message |
davidroux
Joined: 19 Jul 2009 Posts: 11
|
spi help |
Posted: Wed Nov 11, 2009 3:55 pm |
|
|
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
|
|
Posted: Wed Nov 11, 2009 3:57 pm |
|
|
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
|
|
Posted: Wed Nov 11, 2009 4:05 pm |
|
|
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
|
|
Posted: Wed Nov 11, 2009 6:42 pm |
|
|
Configure the same SPI mode in both the Master and Slave (you have mode 0 and 3). |
|
|
davidroux
Joined: 19 Jul 2009 Posts: 11
|
thnanks |
Posted: Wed Nov 11, 2009 11:38 pm |
|
|
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! |
|
|
davidroux
Joined: 19 Jul 2009 Posts: 11
|
|
Posted: Thu Nov 12, 2009 6:54 am |
|
|
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
|
|
Posted: Thu Nov 12, 2009 7:07 am |
|
|
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
|
|
Posted: Thu Nov 12, 2009 11:16 am |
|
|
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
|
|
Posted: Fri Nov 13, 2009 7:17 am |
|
|
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
|
|
Posted: Fri Nov 13, 2009 10:48 am |
|
|
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'. |
|
|
|
|
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
|