Skip to content

Commit 03a034b

Browse files
committed
Added LIS3DSH demo example
1 parent 393fe8e commit 03a034b

File tree

3 files changed

+361
-0
lines changed

3 files changed

+361
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
##
2+
## This file is part of the libopencm3 project.
3+
##
4+
## Copyright (C) 2015 Marco Russi <[email protected]>
5+
##
6+
## This library is free software: you can redistribute it and/or modify
7+
## it under the terms of the GNU Lesser General Public License as published by
8+
## the Free Software Foundation, either version 3 of the License, or
9+
## (at your option) any later version.
10+
##
11+
## This library is distributed in the hope that it will be useful,
12+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
## GNU Lesser General Public License for more details.
15+
##
16+
## You should have received a copy of the GNU Lesser General Public License
17+
## along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
##
19+
20+
BINARY = lis3dsh_demo
21+
22+
LDSCRIPT = ../stm32f4-discovery.ld
23+
24+
include ../../Makefile.include
25+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# README
2+
3+
This is a demo application for the 3-axis accelerometer LIS3DSH and the LEDs on the board using libopencm3.
4+
5+
It's intended for the ST STM32F4DISCOVERY eval board. Rotating the board on each side will turn ON the closest LED to the side parallel to ground. Position the board with LED on top turns ON all the LEDs while facing the board on the ground turns them OFF.
6+
7+
## Board connections
8+
9+
*none required*
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* This file is part of the libopencm3 project.
3+
*
4+
* Copyright (C) 2015 Marco Russi <[email protected]>
5+
*
6+
* This library is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Lesser General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This library is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
21+
/* ---------------- Inclusions ----------------- */
22+
#include <libopencm3/stm32/rcc.h>
23+
#include <libopencm3/stm32/gpio.h>
24+
#include <libopencm3/stm32/spi.h>
25+
26+
27+
28+
29+
/* ---------------- Local Defines ----------------- */
30+
31+
/* LIS3DSH registers addresses */
32+
#define ADD_REG_WHO_AM_I 0x0F
33+
#define ADD_REG_CTRL_4 0x20
34+
#define ADD_REG_OUT_X_L 0x28
35+
#define ADD_REG_OUT_X_H 0x29
36+
#define ADD_REG_OUT_Y_L 0x2A
37+
#define ADD_REG_OUT_Y_H 0x2B
38+
#define ADD_REG_OUT_Z_L 0x2C
39+
#define ADD_REG_OUT_Z_H 0x2D
40+
41+
/* WHO AM I register default value */
42+
#define UC_WHO_AM_I_DEFAULT_VALUE 0x3F
43+
44+
/* ADD_REG_CTRL_4 register configuration value: X,Y,Z axis enabled and 400Hz of output data rate */
45+
#define UC_ADD_REG_CTRL_4_CFG_VALUE 0x77
46+
47+
/* Sensitivity for 2G range [mg/digit] */
48+
#define SENS_2G_RANGE_MG_PER_DIGIT ((float)0.06)
49+
50+
/* LED threshold value in mg */
51+
#define LED_TH_MG (1000) /* 1000mg (1G) */
52+
53+
54+
55+
56+
/* ---------------- Local Macros ----------------- */
57+
58+
/* set read single command. Attention: command must be 0x3F at most */
59+
#define SET_READ_SINGLE_CMD(x) (x | 0x80)
60+
/* set read multiple command. Attention: command must be 0x3F at most */
61+
#define SET_READ_MULTI_CMD(x) (x | 0xC0)
62+
/* set write single command. Attention: command must be 0x3F at most */
63+
#define SET_WRITE_SINGLE_CMD(x) (x & (~(0xC0)))
64+
/* set write multiple command. Attention: command must be 0x3F at most */
65+
#define SET_WRITE_MULTI_CMD(x) (x & (~(0x80)) \
66+
x |= 0x40)
67+
68+
/* Macros for turning LEDs ON */
69+
#define LED_GREEN_ON() (gpio_set(GPIOD, GPIO12))
70+
#define LED_ORANGE_ON() (gpio_set(GPIOD, GPIO13))
71+
#define LED_RED_ON() (gpio_set(GPIOD, GPIO14))
72+
#define LED_BLUE_ON() (gpio_set(GPIOD, GPIO15))
73+
74+
/* Macros for turning LEDs OFF */
75+
#define LED_GREEN_OFF() (gpio_clear(GPIOD, GPIO12))
76+
#define LED_ORANGE_OFF() (gpio_clear(GPIOD, GPIO13))
77+
#define LED_RED_OFF() (gpio_clear(GPIOD, GPIO14))
78+
#define LED_BLUE_OFF() (gpio_clear(GPIOD, GPIO15))
79+
80+
81+
82+
83+
/* ------------- Local functions prototypes --------------- */
84+
85+
static void gpio_setup (void);
86+
static void spi_setup (void);
87+
static void LIS3DSH_init (void);
88+
static void LIS3DSH_write_reg (int, int);
89+
static int LIS3DSH_read_reg (int);
90+
static inline int twoComplToInt16 (int);
91+
92+
93+
94+
95+
/* ------------ Local functions implementation ----------- */
96+
97+
/* Function to setup all used GPIOs */
98+
static void gpio_setup(void)
99+
{
100+
/* Enable GPIOD clock. */
101+
rcc_periph_clock_enable(RCC_GPIOD);
102+
103+
/* Set GPIO12, GPIO13, GPIO14, GPIO15 (in GPIO port D) to 'output push-pull'. */
104+
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO12 | GPIO13 | GPIO14 | GPIO15);
105+
106+
/* LIS3DSH pins map:
107+
PA5 - SPI1_SCK
108+
PA6 - SPI1_MISO
109+
PA7 - SPI1_MOSI
110+
PE3 - CS_SPI
111+
*/
112+
113+
/* Enable GPIOA clock. */
114+
rcc_periph_clock_enable(RCC_GPIOA);
115+
/* set SPI pins as CLK, MOSI, MISO */
116+
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO6 | GPIO7);
117+
/* Push Pull, Speed 100 MHz */
118+
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO5 | GPIO6 | GPIO7);
119+
/* Alternate Function: SPI1 */
120+
gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO6 | GPIO7);
121+
122+
/* Enable GPIOE clock. */
123+
rcc_periph_clock_enable(RCC_GPIOE);
124+
/* set CS as OUTPUT */
125+
gpio_mode_setup(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3);
126+
/* Push Pull, Speed 100 MHz */
127+
gpio_set_output_options(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, GPIO3);
128+
/* set CS high */
129+
gpio_set(GPIOE, GPIO3);
130+
}
131+
132+
133+
/* Function to setup the SPI1 */
134+
static void spi_setup(void)
135+
{
136+
/* Enable SPI1 clock. */
137+
rcc_periph_clock_enable(RCC_SPI1);
138+
139+
/* reset SPI1 */
140+
spi_reset(SPI1);
141+
/* init SPI1 master */
142+
spi_init_master(SPI1,
143+
SPI_CR1_BAUDRATE_FPCLK_DIV_64,
144+
SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
145+
SPI_CR1_CPHA_CLK_TRANSITION_1,
146+
SPI_CR1_DFF_8BIT,
147+
SPI_CR1_MSBFIRST);
148+
/* enable SPI1 first */
149+
spi_enable(SPI1);
150+
}
151+
152+
153+
/* Function to initialise the LIS3DSH */
154+
static void LIS3DSH_init(void)
155+
{
156+
int intRegValue;
157+
158+
/* init SPI1 */
159+
spi_setup();
160+
161+
/* get WHO AM I value */
162+
intRegValue = LIS3DSH_read_reg(ADD_REG_WHO_AM_I);
163+
164+
/* if WHO AM I value is the expected one */
165+
if( intRegValue == UC_WHO_AM_I_DEFAULT_VALUE )
166+
{
167+
/* set output data rate to 400 Hz and enable X,Y,Z axis */
168+
LIS3DSH_write_reg(ADD_REG_CTRL_4, UC_ADD_REG_CTRL_4_CFG_VALUE);
169+
/* verify written value */
170+
intRegValue = LIS3DSH_read_reg(ADD_REG_CTRL_4);
171+
/* if written value is different */
172+
if( intRegValue != UC_ADD_REG_CTRL_4_CFG_VALUE )
173+
{
174+
/* ERROR: stay here... */
175+
while(1);
176+
}
177+
}
178+
else
179+
{
180+
/* ERROR: stay here... */
181+
while(1);
182+
}
183+
}
184+
185+
186+
/* Function to write a register to LIS3DSH through SPI */
187+
static void LIS3DSH_write_reg(int reg, int data)
188+
{
189+
/* set CS low */
190+
gpio_clear(GPIOE, GPIO3);
191+
/* discard returned value */
192+
spi_xfer(SPI1, SET_WRITE_SINGLE_CMD(reg));
193+
spi_xfer(SPI1, data);
194+
/* set CS high */
195+
gpio_set(GPIOE, GPIO3);
196+
}
197+
198+
199+
/* Function to read a register from LIS3DSH through SPI */
200+
static int LIS3DSH_read_reg(int reg)
201+
{
202+
int regValue;
203+
/* set CS low */
204+
gpio_clear(GPIOE, GPIO3);
205+
regValue = spi_xfer(SPI1, SET_READ_SINGLE_CMD(reg));
206+
regValue = spi_xfer(SPI1, 0xFF);
207+
/* set CS high */
208+
gpio_set(GPIOE, GPIO3);
209+
210+
return regValue;
211+
}
212+
213+
214+
/* Transform a two's complement value to 16-bit int value */
215+
static inline int twoComplToInt16(int twoComplValue)
216+
{
217+
int int16Value = 0;
218+
219+
/* conversion */
220+
if(twoComplValue > 32768)
221+
{
222+
int16Value = -(((~twoComplValue) & 0xFFFF) + 1);
223+
}
224+
else
225+
{
226+
int16Value = twoComplValue;
227+
}
228+
229+
return int16Value;
230+
}
231+
232+
233+
/* Main function */
234+
int main(void)
235+
{
236+
int i;
237+
int intValueMgX, intValueMgY, intValueMgZ;
238+
239+
/* setup all GPIOs */
240+
gpio_setup();
241+
242+
/* initialise LIS3DSH */
243+
LIS3DSH_init();
244+
245+
/* infinite loop */
246+
while(1)
247+
{
248+
/* get X, Y, Z values */
249+
intValueMgX = ((LIS3DSH_read_reg(ADD_REG_OUT_X_H) << 8) | LIS3DSH_read_reg(ADD_REG_OUT_X_L));
250+
intValueMgY = ((LIS3DSH_read_reg(ADD_REG_OUT_Y_H) << 8) | LIS3DSH_read_reg(ADD_REG_OUT_Y_L));
251+
intValueMgZ = ((LIS3DSH_read_reg(ADD_REG_OUT_Z_H) << 8) | LIS3DSH_read_reg(ADD_REG_OUT_Z_L));
252+
253+
/* transform X value from two's complement to 16-bit int */
254+
intValueMgX = twoComplToInt16(intValueMgX);
255+
/* convert X absolute value to mg value */
256+
intValueMgX = intValueMgX * SENS_2G_RANGE_MG_PER_DIGIT;
257+
258+
/* transform Y value from two's complement to 16-bit int */
259+
intValueMgY = twoComplToInt16(intValueMgY);
260+
/* convert Y absolute value to mg value */
261+
intValueMgY = intValueMgY * SENS_2G_RANGE_MG_PER_DIGIT;
262+
263+
/* transform Z value from two's complement to 16-bit int */
264+
intValueMgZ = twoComplToInt16(intValueMgZ);
265+
/* convert Z absolute value to mg value */
266+
intValueMgZ = intValueMgZ * SENS_2G_RANGE_MG_PER_DIGIT;
267+
268+
/* set X related LEDs according to specified threshold */
269+
if(intValueMgX >= LED_TH_MG)
270+
{
271+
LED_BLUE_OFF();
272+
LED_ORANGE_OFF();
273+
LED_GREEN_OFF();
274+
LED_RED_ON();
275+
}
276+
else if(intValueMgX <= -LED_TH_MG)
277+
{
278+
LED_BLUE_OFF();
279+
LED_ORANGE_OFF();
280+
LED_RED_OFF();
281+
LED_GREEN_ON();
282+
}
283+
284+
/* set Y related LEDs according to specified threshold */
285+
if(intValueMgY >= LED_TH_MG)
286+
{
287+
LED_BLUE_OFF();
288+
LED_RED_OFF();
289+
LED_GREEN_OFF();
290+
LED_ORANGE_ON();
291+
}
292+
else if(intValueMgY <= -LED_TH_MG)
293+
{
294+
LED_RED_OFF();
295+
LED_GREEN_OFF();
296+
LED_ORANGE_OFF();
297+
LED_BLUE_ON();
298+
}
299+
300+
/* set Z related LEDs according to specified threshold */
301+
if(intValueMgZ >= LED_TH_MG)
302+
{
303+
LED_BLUE_ON();
304+
LED_ORANGE_ON();
305+
LED_RED_ON();
306+
LED_GREEN_ON();
307+
}
308+
else if(intValueMgZ <= -LED_TH_MG)
309+
{
310+
LED_BLUE_OFF();
311+
LED_ORANGE_OFF();
312+
LED_RED_OFF();
313+
LED_GREEN_OFF();
314+
}
315+
316+
/* Wait a bit... */
317+
for (i = 0; i < 100; i++)
318+
{
319+
__asm__("nop");
320+
}
321+
}
322+
323+
return 0;
324+
}
325+
326+
327+
/* End of file */

0 commit comments

Comments
 (0)