![]() | ![]() | ![]() |
| |||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
![]() |
| | Tools |
| | #1 |
|
Hi there! ![]() It's been a while since I bugged you people with a question and now I have another one. It relates to SPI communication. I am trying to read values from a Freescale accelerometer (MMA7455L) using a PIC 18F4550 and SPI. To that end, I wrote some simple code. Now, it doesn't seems to work as the program seems stuck when trying to read the value I just wrote into a register of the MMA7455L. What I would like you to do is take a look at my code and tell me if you think it's valid. If you think it's Ok then I can start thinking about bugging the Freescale people. Many thanks! - Florian Edit - just to add a few details. Because MMA7455L operates in slave mode, I am using bit 6 on PORTD to toggle SPI transmission. Also, the write command seems to work as when I am debugging it exits the loop, however the code gets stuck when trying to read the value written into the register (testing to see if the code works). The clock is FOSC/4, so about 5MHz as I am using a 20MHz crystal (that speed is Ok for the MMA7455L if the VDD is > 2.4 and it is in my case). Code: #include <p18f4550.h>
#include <delays.h>
#pragma config WDT = OFF, FOSC = INTOSC_HS, LVP=OFF
unsigned char val=0;
void picdelay (unsigned char n);
void ledonoff ();
unsigned char spi_r(unsigned char reg);
void spi_w(unsigned char regaddr, unsigned char regdata);
void main (void)
{
// Make all bits on the Port D (LEDs) output bits.
TRISD = 0;
//initializing SPI operation
SSPSTAT=0xC0; //11xxxxxx (x = don't care)
SSPCON1=0x30; //0011xxxx (x = don't care)
//Enable I/O
//SDO must have TRISC<7> bit cleared
TRISCbits.TRISC7=0;
//SCK must have TRISB<1> bit cleared.
TRISBbits.TRISB1=0;
//Set up MMA7455L operation mode by writing to hex addr 16, hex value 05 (2g, 4 wires)
spi_w(22,5); // 22 = 0x16, 5 = 0x05
while (1) {
val = spi_r(22); // read value back from register and if expected value flash the LED
if(val==5){ledonoff();}
};
}// End of the main program
//SPI write command function reg - 1rrrrrrx (bit 7 is 1, next 6 bits reg address and a don't care)
void spi_w(unsigned char regaddr, unsigned char regdata)
{
unsigned char tmp;
PORTDbits.RD6 = 0; // pull the CS low to start SPI transmission
SSPBUF=(((regaddr&0x3F)<<1)|0x80); // send register address to the accelerometer with write command
while(!SSPSTATbits.BF);// wait for transfer
tmp=SSPBUF; // reading SSPBUF clears the BF bit
SSPBUF=regdata; // send data into the accelerometer register
while(!SSPSTATbits.BF);
tmp=SSPBUF; // reading SSPBUF clears the BF bit
PORTDbits.RD6 = 1; // pull the CS high to stop SPI transmission
}
//SPI read function (send read register commands to the accelerometer and output resultant read byte)
unsigned char spi_r(unsigned char reg)
{
unsigned char temp;
PORTDbits.RD6 = 0; // pull the CS low to start transmission
SSPBUF=((reg&0x3F)<<1); // // send register affress to the accelerometer with read command
while(!SSPSTATbits.BF);// wait for transmit to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
while(!SSPSTATbits.BF); // wait for receive to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
PORTDbits.RD6 = 1; // pull the CS high to stop transmission
return temp;
}
Last edited by WizzBall; 12th June 2009 at 11:01 PM. | |
| |
| | #2 |
|
Hello i think you don't use the good register: SSPSTATbits.BF but SSPIF on PIR1bits.SSPIF I have the same accelerometer (MMA7455L) but using a PIC 18F24K20 and with this code i can read, what i write on SPI... Code: //SPI write command function
void spi_w(unsigned char reg, unsigned char data)
{ unsigned char x;
CS=0;
SSPBUF=(((reg &0x3F)<<1)|0x80);
while (!SSPIF); //wait for transmission complete
x=SSPBUF; //dummy read
SSPBUF=data;
while (!SSPIF); //wait for transmission complete
x=SSPBUF;
CS=1;
}
//SPI read function
unsigned char spi_r(unsigned char reg)
{ unsigned char x;
CS=0;
SSPBUF = 0x00; // initiate bus cycle
while ( !SSPIF ); // wait until cycle complete
CS=1;
return ( SSPBUF ); // return with byte read
}
Code: char Xdata
while (1) {
Xdata=spi_r(0x06); //Read X output from Sensor
DelayUs(10);
if(Xdata<=0x00)LED=1;
else LED=0;
}
}
sorry for my english... | |
| |
| | #3 |
|
Many thanks MacArell! That was indeed the problem! Looks like it's just the two of us on this thing but I think I know why your code is not working. I believe it is purely a programming issue. One thing to keep in mind is that when the 'if' condition is not satisfied and is not followed by an 'else if' statement, the PIC will exit the loop. So in your case, when your 'if' statement is not true, it will never get to evaluate your 'else' statement. You can do it this way and it works just fine for me: Code: while (1) {
val=0;// reset value
PORTDbits.RD7 = 0;// turn LED ON
val = spi_r(22); // read value from register
if(val==5){PORTDbits.RD7 = 1;}// turn LED OFF
else if(val!=5) {PORTDbits.RD7 = 0;}// turn LED ON
};
![]() - Florian Last edited by WizzBall; 8th July 2009 at 03:02 AM. | |
| |
| | #4 |
|
Thank Florian for your reply! But i think my last post wasn't good, because on my SDO (MISO, pin 12 connected to my SDO pin PIC) and SDI (MOSI, pin 13 connect to my SDI pin PIC) i have nothing with an oscilloscope (it's good on SCL...) and when i unconnect the MMA7455L my LED work like the MMA7455L was connected... My PIC is master and with SPI 4 wire mode...For information: Code: void initialise_SPI()
{
SSPEN = 0; //Enable bit must be cleared to configure SPI
TRISC = TRISC | 0b00010000; //Setup the TRIS register
CKP = 0; //IDLE state for clock is a low level
CKE = 1; //Output data changes on clock transition from active to idle
SMP = 0; //Input data sampled at the middle of data output time
SSPCON1 = SSPCON1 | 0b00000010; //Speed: Fosc/64
SSPEN = 1; //Enable the serial port
}
Code: //SPI write command function
void spi_w(unsigned char reg, unsigned char data){
unsigned char x;
CS=lo;
SSPBUF=(((reg &0x3F)<<1)|0x80);
while (!SSPIF); //wait for transmission complete
x=SSPBUF; //dummy read
SSPBUF=data;
while (!SSPIF); //wait for transmission complete
x=SSPBUF;
CS=hi;
}
//SPI read function
unsigned char spi_r(unsigned char reg){
CS=lo;
SSPBUF = 0x00; // initiate bus cycle
while ( !BF ); // wait until cycle complete
CS=hi;
return ( SSPBUF ); // return with byte read
}
the 'if' condition is satisfied when followed by an 'else' alone... | |
| |
| | #5 |
|
Hi MacArell, please look at my first post to see the proper way of doing a read on the MMA7455L. You are first writing to the MMA7455L to tell it what register to read from and then you are reading the value sent back from MMA7455L. I am not sure if your problem stems from that but try it this way, see if it works as it seems to work for me. As to the 'else' working for you instead of 'else if', well I'm glad it works, it didn't do it for me .Hope this helps! Last edited by WizzBall; 8th July 2009 at 09:02 AM. | |
| |
| | #6 |
|
heh WizzBall is correct... have you notice you are not using the reg char from: "unsigned char spi_r(unsigned char reg)" Code: unsigned char spi_r(unsigned char reg){
CS=lo;
SSPBUF = 0x00; // initiate bus cycle
while ( !BF ); // wait until cycle complete
CS=hi;
return ( SSPBUF ); // return with byte read
}
i made changes for you from the first posters code here is what yours should look like: Code: unsigned char spi_r(unsigned char reg)
{
unsigned char temp;
CS=lo;
SSPBUF=((reg&0x3F)<<1); // send register affress to the accelerometer with read command
while(!SSPSTATbits.BF); // wait for transmit to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
while(!SSPSTATbits.BF); // wait for receive to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
CS=hi; // pull the CS high to stop transmission
return temp;
}
__________________ AtomSofts eBay Store AtomSoftTech: C18 TIPS & TRICKS v9 PDF My Name: Jason Lopez http://atomsofttech.info/ | My YouTube Videos! My Favorite Store: dipmicro Electronics Last edited by AtomSoft; 8th July 2009 at 11:53 AM. | |
| |
| | #7 |
|
Hi AtomSoft, thank's On my "SPI read function" code, i do a mistake when i cut and copy code, now my code it's: Code: //SPI read function (send read register commands to the accelerometer and output resultant read byte)
unsigned char spi_r(unsigned char reg)
{
unsigned char temp;
CS = lo; // pull the CS low to start transmission
SSPBUF=((reg&0x3F)<<1); // // send register address to the accelerometer with read command
while(!SSPIF);// wait for transmit to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
while(!SSPIF); // wait for receive to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
CS = hi; // pull the CS high to stop transmission
return temp;
}
Last edited by MacArell; 8th July 2009 at 03:00 PM. | |
| |
| | #8 |
|
That should work, just correct "'affress"' back to "'address", I made a typo .
| |
| |
| | #9 |
|
OK Florian //No comment Last edited by MacArell; 8th July 2009 at 03:01 PM. | |
| |
| | #10 |
|
@Florian or other: How you connect you PIC (mine: 18F24K20) to Accelerometer? for me it's 1rst case: PIC ---> MMA7455L SCL (14) --> SCL (14) SDO (16) --> SDO (12) SDI (15) --> SDI (13) RB3 (24) --> CS (7) or you think: PIC ---> MMA7455L SCL (14) --> SCL (14) SDO (16) --> SDI (13) SDI (15) --> SDO (12) RB3 (24) --> CS (7) Thank's Last edited by MacArell; 8th July 2009 at 04:48 PM. | |
| |
| | #11 |
|
Hi MacArell, If it's the first case, it is wrong. Output from the master (PIC) should go into the input of the slave and viceversa. So you should connect pins as per your second arrangement. Here is a link to the Freescale document that explains in detail how to connect the accelerometer when using SPI: http://www.freescale.com/files/senso...ote/AN3468.pdf - Florian | |
| |
| | #12 |
|
Thank you Florian, I change my SDI and SDO pin but don't working again ![]() In your first Code, where do you make SDI as input (for you SDI is RB0 with TRISBbits.TRISB0=1; )? For me the SDI input don't reply... no signal on pin from Accelerometer. my init code: Code: void init_ports()
{ ANSEL=0;
ANSELH=0;
//Ports Direction: "1" inputs and "0" outputs
TRISA=0b11111000; //config portA
TRISB=0b11110111; //config portB RB3=0 (CS SPI)
TRISC=0b00010000; //config portC SCK(RC3)=0, SDI(RC4)=1, SDO(RC5)=0
}
void init_SPI()
{
OpenSPI(FOSC_4,MODE_00,SMPEND); //Mode 00 & SMPEND: CKE=1, CKP=0 & SMP=1
}
![]() EDIT: I found solution!!! ![]() With all init upstair... With new code for read and write on SPI: Code: //SPI write command function reg
void spi_w(unsigned char regaddr, unsigned char regdata)
{
unsigned char tmp;
CS = lo; // pull the CS low to start SPI transmission
SSPBUF=(((regaddr&0x3F)<<1)|0x80); // send register address to the accelerometer with write command
while(!BF); // wait for transfer
tmp=SSPBUF; // reading SSPBUF clears the BF bit
SSPBUF=regdata; // send data into the accelerometer register
while(!BF);
tmp=SSPBUF; // reading SSPBUF clears the BF bit
CS = hi; // pull the CS high to stop SPI transmission
}
//SPI read function
unsigned char spi_r(unsigned char reg)
{
unsigned char temp;
CS=lo;
SSPBUF=((reg&0x3F)<<1); // send register address to the accelerometer with read command
while(!BF); // wait for transmit to finish
SSPBUF = 0x00; // reading SSPBUF clears the BF bit
while(!BF); // wait for receive to finish
temp=SSPBUF; // reading SSPBUF clears the BF bit
CS=hi; // pull the CS high to stop transmission
return temp;
}
Last edited by MacArell; 17th July 2009 at 07:59 AM. | |
| |
| | #13 |
|
Thank you MacArell! Here is the solution I developed using some of the Tips and Tricks from AtomSoft's document which I modified for my needs (thanks again Jason! ).I became frustrated with the 'support' from both Microchip and Freescale so this is SPI done in software. The good thing is it can be used with almost any PIC or even other micros with a bit of adjustment. I will try your solution and post some feedback. Code: #include <p18f4550.h>
#include <delays.h>
#pragma config FOSC = HS // use High Speed crystal (20MHz) - not using PLL right now
#pragma config CPUDIV = OSC4_PLL6 // Set speed for 5MHz (divide crystal speed by 4, PLL by 6)
#pragma config PWRT = ON //Power up timer is ON
#pragma config WDT = OFF // Watchdog timer is OFF
#pragma config LVP = ON // Low Voltage Programming ON
#pragma config BOR = OFF //Brown out reset is OFF
#pragma config DEBUG = ON //Debug is ON
#pragma config VREGEN = OFF //Internal voltage regulator is off (not using USB yet)
#define CS LATDbits.LATD0 //Chip Select Latch
#define SCL LATCbits.LATC0 //Clock Latch
#define SDO LATCbits.LATC1 //Data Out Latch
#define SDI PORTCbits.RC2 //Data In Port
#define CST TRISDbits.TRISD0 //Chip Select TRIS
#define SCLT TRISCbits.TRISC0 //Clock TRIS
#define SDOT TRISCbits.TRISC1 //Data Out TRIS
#define SDIT TRISCbits.TRISC2 //Data In TRIS
unsigned char val=0;
void main(void);
void initSPI(void);
unsigned char ReadSPI(unsigned char address);
void WriteSPI(unsigned char address, unsigned char data);
unsigned char SPI_RByte(void);
void SPI_WByte(unsigned char data);
void main (void)
{
// Make bit 7 the Port D (LED) output bit.
TRISDbits.TRISD7 = 0;
//SPI init
initSPI();
while (1) {
val=0;// reset value
LATDbits.LATD7 = 0;// turn LED OFF
//Set up MMA7455L operation mode by writing to hex addr 16, hex value 05 (2g, 4 wires)
WriteSPI(0x16,0x05);
val = ReadSPI(0x16); // read value back from register and if expected value turn ON the LED
if(val==0x05){LATDbits.LATD7 = 1;Delay10KTCYx(200);}// turn LED ON
else if(val!=0x05) {LATDbits.LATD7 = 0;}// turn LED ON
};
}// End of the main program
void initSPI(void){
SCLT = 0; //Set the SCL (CLOCK) pin to output
SDOT = 0; //Set the SDO (DATA OUT) pin to output
SDIT = 1; //Set the SDI (DATA IN) pin to input
CST = 0; //Set the CS (Chip Select) pin to output
CS = 0; //Set Chip Select Low
SDO = 0; //Set Serial Data Out Low
SCL = 0; //Set Serial Clock Low
}
void SPI_WByte(unsigned char data){
char x;
for(x=0;x<8;x++){ //Loop 8 bits
SCL = 0; //Clock Low
SDO = 0; //Data Low
if((data & 0x80) != 0) //Clear entire byte except bit 7 and check if byte is greater than 0
SDO = 1; //Set the Data Out to HIGH
Delay10TCY(); //Delay 5uS
SCL = 1; //Clock High
Delay10TCY(); //Delay 5uS
data <<= 1; //Shift data bit out to the right
}
}
unsigned char SPI_RByte(void){
char x,data;
for(x=0;x<8;x++){ //Loop 8 bits
SCL = 0; //Clock Low
Delay10TCY(); //5uS delay
data <<= 1; //Shift 1 bit to the left
data &= 0xFE; //Clear BIT 0 from byte without touching the rest
if(SDI) //if the Serial Data In is HIGH do below if not then leave it 0
data |= 1; //OR in a 1 into out byte
Delay10TCY(); //delay 5uS
SCL = 1; //Clock High
}
return data; //return our data
}
void WriteSPI(unsigned char address, unsigned char data){
SCL = 1; //Clock High
CS = 0; //Chip Select Low
address=(((address&0x3F)<<1)|0x80);
SPI_WByte(address); //Write our address
SPI_WByte(data); //Write our data
CS = 1; //Chip Select High
}
unsigned char ReadSPI(unsigned char address){
unsigned char tmp;
SCL = 1; //Clock High
CS = 0; //Chip Select Low
address=((address<<1)&0x7f);// Send read command together with reg address
SPI_WByte(address); //Write our address to read from
tmp = SPI_RByte(); //Get the byte from the device
CS = 1; //Chip Select High
return tmp; //Return tmp
}
__________________ Florian | |
| |
|
| Tags |
| freescale, mma7455l, pic, spi |
| Thread Tools | |
| Display Modes | |
| |
Similar | ||||
| Title | Starter | Forum | Replies | Latest |
| Does Freescale MPC561 drive Data pins 23-0 when instructed to write a byte? | naseeam | Micro Controllers | 0 | 2nd September 2008 05:11 PM |
| Freescale Semiconductors | shermaine | General Electronics Chat | 2 | 19th September 2005 07:16 PM |
| Keyscanning Routine Problem with Freescale Motorola HCS08. | GraveYard_Killer | Micro Controllers | 0 | 30th March 2005 02:41 PM |