View previous topic :: View next topic |
Author |
Message |
Guest
|
SPI and LIS3LV02DL Accelerometer |
Posted: Sat Feb 21, 2009 3:40 pm |
|
|
Hello I'm interfacing to ST LIS3LV02DL SPI Accelerometer and I am having some problems getting my code to work. MSB and LSB read -1 in hyperterminal and value reads FF. I'm not worried about the exact values since I know my code isn't done completely to get G values. Also I tried to read the "Who am I" register but still get nothing in return. I did have working before with a basic stamp. Any ideas??
Using MPLAB 8.15 and CCS 4.068
.H File:
Code: | #include <18F4520.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES INTRC //Internal RC Osc
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES PBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES MCLR //Master Clear pin enabled
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8) |
.C File:
Code: |
#include "C:Documents\SPI Accel\main2.h"
#include <float.h>
#include <math.h>
#include <string.h>
int8 msb;
int8 lsb;
int16 value;
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_4MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
delay_ms(1000);
output_high(PIN_A0);
output_low(PIN_A0); //Enable Accel
spi_write(0x21); //Write Cntrl Reg Addr
spi_write(0x20); //data written to Cntrl Reg Add
output_high(PIN_A0);
While(1)
{
output_high(PIN_A0);
output_low(PIN_A0); //enable accel
spi_write(0xA8); //write to x lowbyte addr
lsb=spi_read(); //read in value from addr
output_high(PIN_A0);
delay_ms(100);
output_low(PIN_A0); //enable accel
spi_write(0xA9); //write to x highbyte addr
msb=spi_read(); //read in value form addr
output_high(PIN_A0);
delay_ms(1000);
value= make16(msb,lsb);
printf("MSB %d LSB %d total %x \r\n",msb,lsb,value); //Display data for debugging
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 21, 2009 4:53 pm |
|
|
Look at this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=37644
1. Your SPI mode setting is wrong. The accelerometer chip uses Mode 3
but you have it set for Mode 2. See how to do it correctly in that thread.
2. Your spi_read() statements don't have a 0 parameter, so no clock
will be generated by the master PIC. This means the PIC will not read
any data from the accelerometer chip during the spi read operation.
You need to add the 0 parameter to generate the SPI clock. See the other
thread for an example. |
|
|
Guest
|
|
Posted: Sat Feb 21, 2009 5:59 pm |
|
|
Ok some progress has been made. After looking at that link I added into my code the following so I could switch between them easily. Now in that link it says it operates on mode 3 but when I use that it doesn't work. I change to mode 1 and access the "who am I" register and it returns the correct value. But I still only get 0 from msb and lsb no matter how I move the accelerometer.
Code: | // SPI modes
#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) |
Any ideas about the mode? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 21, 2009 6:58 pm |
|
|
Post your latest test program. (Same as in the first post, except with
modifications). |
|
|
Guest
|
|
Posted: Sat Feb 21, 2009 7:21 pm |
|
|
here is my modified program.
Code: | #include <float.h>
#include <math.h>
#include <string.h>
// SPI modes
#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)
int8 msb;
int8 lsb;
int16 value;
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_MODE_1|SPI_CLK_DIV_16);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_4MHZ|OSC_INTRC|OSC_31250|OSC_PLL_OFF);
//delay_ms(1000);
output_high(PIN_A0);
output_low(PIN_A0);
spi_write(0x21);
spi_write(0x20);
output_high(PIN_A0);
//output_low(PIN_A0);
//spi_write(0x20);
//spi_write(0x80);
//output_high(PIN_A0);
While(1)
{
output_high(PIN_A0);
output_low(PIN_A0);
spi_write(0x8F); //register address for "who am I"
lsb=spi_read(0x00);
output_high(PIN_A0);
delay_ms(100);
output_low(PIN_A0);
spi_write(0x29|0x80);
msb=spi_read(0x00);
output_high(PIN_A0);
delay_ms(1000);
value= make16(msb,lsb);
printf("MSB %d LSB %d total %x \r\n",msb,lsb,value);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 22, 2009 12:01 am |
|
|
Quote: | output_high(PIN_A0);
output_low(PIN_A0);
spi_write(0x21);
spi_write(0x20);
output_high(PIN_A0);
//output_low(PIN_A0); |
This code here doesn't look correct. You are writing 0x20 to register 0x21.
What will that do ? Register 0x21 is CTRL_REG2.
You should be writing to register 0x20, to remove the power-down
condition and turn on the chip.
You need to read the LIS3LV02DL data sheet and look at the code and
the discussion in the previous link. It explains how the default state of
the LIS3LV02DL is to be in power-down mode, and how you must write
to register 0x20 to go into power-on mode.
Also, there is sample code here:
http://www.sparkfun.com/datasheets/Sensors/LIS3LV02DQ-Tester.zip
See the LIS3LV02DQ-Tester.c file. It's not written in CCS. It's for some
other compiler. But you can get some good ideas of how the chip
operates. For example, it shows that they read the "Who am I" register
in the main() code. |
|
|
Guest
|
|
Posted: Sun Feb 22, 2009 7:09 am |
|
|
output_high(PIN_A0);
output_low(PIN_A0);
spi_write(0x21);
spi_write(0x20);
output_high(PIN_A0);
Ok maybe I'm not understanding how the write command works in CCS. With the code above I am enabling the accelerometer then I am writing to the 0x21 register and then writing the value of 0x20 into the 0x21 register is that correct?
I also found a mistake in my code where I commented out the part when I am writing to the 0x20 register with the value 0x80. This will turn the device on but it will disable the x,y,z axis.
Any ideas also on why mode 1 works and 3 doesn't? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 22, 2009 4:53 pm |
|
|
I don't know. According to the LIS3LV02DL data sheet, it's SPI mode 3. |
|
|
Guest
|
|
Posted: Sun Feb 22, 2009 9:50 pm |
|
|
Ok false hope. I decided to check the values I stored in 0x20 and 0x21 by reading them in the msb and lsb section of my code and all I get is a -1 which was my original problem. I dont know why mode 1 worked for reading the "who am I register". I need to get a saleae logic analyzer I think.
Below is my basic stamp code which had it working.
Code: | ' {$STAMP BS2}
' {$PBASIC 2.5}
' -----[ I/O Definitions ]-------------------------------------------------
Clock PIN 0
SerDataIn PIN 1
SerDataOut PIN 2
EnableAccel PIN 3
Enable PIN 5
' -----[ Constants ]-------------------------------------------------------
Blank CON $0 ' Special Decode characters for MC14489
' -----[ Variables ]-------------------------------------------------------
myoutput VAR Word
config VAR Byte ' decode configuration for MC14489
dpCtrl VAR Nib ' decimal point control for MC14489
digit5 VAR Nib ' segs - digit 5 (this one is not used)
digit4 VAR Nib
digit3 VAR Nib
digit2 VAR Nib
digit1 VAR Nib ' segs - digit 1
ZinH VAR myoutput.HIGHBYTE
ZinL VAR myoutput.LOWBYTE
dummy1 VAR Word
A VAR Byte
B VAR Byte
' -----[ Initialization ]--------------------------------------------------
Reset:
HIGH EnableAccel ' disable MC14489
HIGH Enable
digit1 = 0
digit2 = 0
digit3 = 0
digit4 = 0
digit5 = 0 ' Always 0 (not used)
config = Blank
config = %1 ' To setup for digits only (see
' MC14489 documentation
dpCtrl = %0000
PAUSE 1000 ' Set the display to bright
ResetEnd:
GOSUB Update_Cfg
GOSUB Update_Segs
PAUSE 1000
GOSUB turnon
LOW EnableAccel '
SHIFTOUT SerDataIn, Clock, MSBFIRST, [$21,$00]
HIGH EnableAccel
DO
GOSUB inputdata
GOSUB Update_Cfg
GOSUB Update_Segs
LOOP '
END
' Update LIS3 configuration register
turnon:
LOW EnableAccel ' enable LIS3
SHIFTOUT SerDataIn, Clock, MSBFIRST, [$20,$C7] ' send config register
HIGH EnableAccel ' disable lIS3
RETURN
' GET DATA FROM LIS3
inputdata:
LOW EnableAccel
SHIFTOUT SerDataIn, Clock, MSBFIRST, [$A8]
SHIFTIN SerDataOut,Clock, MSBPRE, [ZinL]
HIGH EnableAccel
LOW EnableAccel
SHIFTOUT SerDataIn, Clock, MSBFIRST, [$A9]
SHIFTIN SerDataOut,Clock, MSBPRE, [ZinH]
HIGH EnableAccel
dummy1=(myoutput*/257)
'DEBUG BIN ? ZinH
'DEBUG BIN ? B
'DEBUG BIN ? ZinL
DEBUG DEC ? myoutput
'DEBUG BIN ? A
DEBUG DEC ? dummy1
PAUSE 100
RETURN |
Code isn't commented perfectly.
The only other problem I think it could be is my basic pic chip setup such as clock and fuses. Any ideas? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1933 Location: Norman, OK
|
|
Posted: Sun Feb 22, 2009 9:56 pm |
|
|
I have the Saleae Logic Analyzer and I'm very happy with it. Works well and has been invaluable when debugging SPI, I2C and (recently added support in Ver .28) 1-wire applications. Highly recommended. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 22, 2009 9:57 pm |
|
|
Quote: | Clock PIN 0
SerDataIn PIN 1
SerDataOut PIN 2
EnableAccel PIN 3
Enable PIN 5 |
Post a list of the connections between the PIC and the LIS3LV02DL.
Post the actual pin numbers used on the PIC and the LIS3LV02DL. |
|
|
Guest
|
|
Posted: Mon Feb 23, 2009 6:55 am |
|
|
LIS3LV02DL Adapter Board Pic
Pin 22(SDO)------> Pin 23(SDI RC4)
Pin 21(SDI)--------> Pin 24(SDO RC5)
Pin 20(SCL/CLK)--> Pin 18(CLK RC3)
Pin 19(CS)---------> Pin 2(A0 'CS')
Between the adapter board and the Pic I use max3378 level shifter. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 23, 2009 2:16 pm |
|
|
Your C source code is not a translation of the Basic code.
Here's the Basic code that writes to CTRL_REG1 (20h). It's writing 0xC7
to the register.
Code: |
Reset:
HIGH EnableAccel ' disable MC14489
HIGH Enable
digit1 = 0
.
.
.
PAUSE 1000
.
.
.
Update LIS3 configuration register
turnon:
LOW EnableAccel ' enable LIS3
SHIFTOUT SerDataIn, Clock, MSBFIRST, [$20,$C7] ' send config register
HIGH EnableAccel ' disable lIS3
RETURN
|
Notice how the Basic code sets the Enable lines high, at the start of the
program. Then it waits 1000 ms.
Here's your translation of it. You're not doing an exact copy of it.
The delay is in the wrong position. And then, you're not writing 0xC7
to the control register #1. In fact, the register order is incorrect in
the following code. The first write operation should have a parameter
of 0x20. The 2nd operation should have a parameter of 0xC7.
Quote: |
delay_ms(1000);
output_high(PIN_A0);
output_low(PIN_A0); //Enable Accel
spi_write(0x21); //Write Cntrl Reg Addr
spi_write(0x20); //data written to Cntrl Reg Add
output_high(PIN_A0);
|
I mean, if you had a working program in Basic it should have been
translated verbatim to C, or as nearly as possible. Also note that the
Basic program is using software SPI, not hardware. This sample code
from Sparkfun has routines for software SPI:
http://www.sparkfun.com/datasheets/Sensors/LIS3LV02DQ-Tester.zip
Look at the spi_comm() routine. It's called by the read_register()
and write_register() routines. These routines can easily be translated
to CCS. |
|
|
Guest
|
|
Posted: Mon Feb 23, 2009 8:08 pm |
|
|
Ok I have it working now in MODE3. I used a saleae logic analyzer to verify what I was sending out and reading back. I havent exactly done the correct calulations to get good data but the main communication is working.
The Problem: I have two different protoboards with the PIC on one and eveything else on the other. When using the logic analyzer I noticed a whole bunch of garbage so I made my wires short as possible and connected the ground and VCC buses together. This has fixed my problems.
Thanks for all your help PCM Programmer!!
Also to anyone having SPI, I2c or serial issues get Saleae Logic Analyzer....will save you hours of debugging time.
Thanks Again |
|
|
|