Added STM32F4-Discovery utilities
[fw/stlink] / example / stm32f4 / Utilities / STM32F4-Discovery / stm32f4_discovery_lis302dl.c
1 /**
2   ******************************************************************************
3   * @file    stm32f4_discovery_lis302dl.c
4   * @author  MCD Application Team
5   * @version V1.0.0
6   * @date    19-September-2011
7   * @brief   This file provides a set of functions needed to manage the LIS302DL
8   *          MEMS accelerometer available on STM32F4-Discovery Kit.
9   ******************************************************************************
10   * @attention
11   *
12   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
13   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
14   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
15   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
16   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
17   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
18   *
19   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
20   ******************************************************************************  
21   */
22
23 /* Includes ------------------------------------------------------------------*/
24 #include "stm32f4_discovery_lis302dl.h"
25 //ADDED BY ME!!!!!!!!!!!!!!!!!!!!
26 #include "stm32f4xx_conf.h"
27
28 /** @addtogroup Utilities
29   * @{
30   */ 
31
32 /** @addtogroup STM32F4_DISCOVERY
33   * @{
34   */ 
35
36 /** @addtogroup STM32F4_DISCOVERY_LIS302DL
37   * @{
38   */
39
40
41 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_TypesDefinitions
42   * @{
43   */
44
45 /**
46   * @}
47   */
48
49 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Defines
50   * @{
51   */
52 __IO uint32_t  LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT;   
53
54 /* Read/Write command */
55 #define READWRITE_CMD              ((uint8_t)0x80) 
56 /* Multiple byte read/write command */ 
57 #define MULTIPLEBYTE_CMD           ((uint8_t)0x40)
58 /* Dummy Byte Send by the SPI Master device in order to generate the Clock to the Slave device */
59 #define DUMMY_BYTE                 ((uint8_t)0x00)
60
61 /**
62   * @}
63   */
64
65 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Macros
66   * @{
67   */
68
69 /**
70   * @}
71   */ 
72   
73 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Variables
74   * @{
75   */ 
76
77 /**
78   * @}
79   */
80
81 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_FunctionPrototypes
82   * @{
83   */
84 static uint8_t LIS302DL_SendByte(uint8_t byte);
85 static void LIS302DL_LowLevel_Init(void);
86 /**
87   * @}
88   */
89
90 /** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Functions
91   * @{
92   */
93
94
95 /**
96   * @brief  Set LIS302DL Initialization.
97   * @param  LIS302DL_Config_Struct: pointer to a LIS302DL_Config_TypeDef structure 
98   *         that contains the configuration setting for the LIS302DL.
99   * @retval None
100   */
101 void LIS302DL_Init(LIS302DL_InitTypeDef *LIS302DL_InitStruct)
102 {
103   uint8_t ctrl = 0x00;
104   
105   /* Configure the low level interface ---------------------------------------*/
106   LIS302DL_LowLevel_Init();
107   
108   /* Configure MEMS: data rate, power mode, full scale, self test and axes */
109   ctrl = (uint8_t) (LIS302DL_InitStruct->Output_DataRate | LIS302DL_InitStruct->Power_Mode | \
110                     LIS302DL_InitStruct->Full_Scale | LIS302DL_InitStruct->Self_Test | \
111                     LIS302DL_InitStruct->Axes_Enable);
112   
113   /* Write value to MEMS CTRL_REG1 regsister */
114   LIS302DL_Write(&ctrl, LIS302DL_CTRL_REG1_ADDR, 1);
115 }
116
117 /**
118   * @brief  Set LIS302DL Internal High Pass Filter configuration.
119   * @param  LIS302DL_Filter_ConfigTypeDef: pointer to a LIS302DL_FilterConfig_TypeDef 
120   *         structure that contains the configuration setting for the LIS302DL Filter.
121   * @retval None
122   */
123 void LIS302DL_FilterConfig(LIS302DL_FilterConfigTypeDef *LIS302DL_FilterConfigStruct)
124 {
125   uint8_t ctrl = 0x00;
126   
127   /* Read CTRL_REG2 register */
128   LIS302DL_Read(&ctrl, LIS302DL_CTRL_REG2_ADDR, 1);
129   
130   /* Clear high pass filter cut-off level, interrupt and data selection bits*/
131   ctrl &= (uint8_t)~(LIS302DL_FILTEREDDATASELECTION_OUTPUTREGISTER | \
132                      LIS302DL_HIGHPASSFILTER_LEVEL_3 | \
133                      LIS302DL_HIGHPASSFILTERINTERRUPT_1_2);
134   /* Configure MEMS high pass filter cut-off level, interrupt and data selection bits */                     
135   ctrl |= (uint8_t)(LIS302DL_FilterConfigStruct->HighPassFilter_Data_Selection | \
136                     LIS302DL_FilterConfigStruct->HighPassFilter_CutOff_Frequency | \
137                     LIS302DL_FilterConfigStruct->HighPassFilter_Interrupt);
138   
139   /* Write value to MEMS CTRL_REG2 register */
140   LIS302DL_Write(&ctrl, LIS302DL_CTRL_REG2_ADDR, 1);
141 }
142
143 /**
144   * @brief Set LIS302DL Interrupt configuration
145   * @param  LIS302DL_InterruptConfig_TypeDef: pointer to a LIS302DL_InterruptConfig_TypeDef 
146   *         structure that contains the configuration setting for the LIS302DL Interrupt.
147   * @retval None
148   */
149 void LIS302DL_InterruptConfig(LIS302DL_InterruptConfigTypeDef *LIS302DL_IntConfigStruct)
150 {
151   uint8_t ctrl = 0x00;
152   
153   /* Read CLICK_CFG register */
154   LIS302DL_Read(&ctrl, LIS302DL_CLICK_CFG_REG_ADDR, 1);
155   
156   /* Configure latch Interrupt request, click interrupts and double click interrupts */                   
157   ctrl = (uint8_t)(LIS302DL_IntConfigStruct->Latch_Request| \
158                    LIS302DL_IntConfigStruct->SingleClick_Axes | \
159                    LIS302DL_IntConfigStruct->DoubleClick_Axes);
160   
161   /* Write value to MEMS CLICK_CFG register */
162   LIS302DL_Write(&ctrl, LIS302DL_CLICK_CFG_REG_ADDR, 1);
163 }
164
165 /**
166   * @brief  Change the lowpower mode for LIS302DL
167   * @param  LowPowerMode: new state for the lowpower mode.
168   *   This parameter can be one of the following values:
169   *     @arg LIS302DL_LOWPOWERMODE_POWERDOWN: Power down mode
170   *     @arg LIS302DL_LOWPOWERMODE_ACTIVE: Active mode  
171   * @retval None
172   */
173 void LIS302DL_LowpowerCmd(uint8_t LowPowerMode)
174 {
175   uint8_t tmpreg;
176   
177   /* Read CTRL_REG1 register */
178   LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
179   
180   /* Set new low power mode configuration */
181   tmpreg &= (uint8_t)~LIS302DL_LOWPOWERMODE_ACTIVE;
182   tmpreg |= LowPowerMode;
183   
184   /* Write value to MEMS CTRL_REG1 regsister */
185   LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
186 }
187
188 /**
189   * @brief  Data Rate command 
190   * @param  DataRateValue: Data rate value
191   *   This parameter can be one of the following values:
192   *     @arg LIS302DL_DATARATE_100: 100 Hz output data rate 
193   *     @arg LIS302DL_DATARATE_400: 400 Hz output data rate    
194   * @retval None
195   */
196 void LIS302DL_DataRateCmd(uint8_t DataRateValue)
197 {
198   uint8_t tmpreg;
199   
200   /* Read CTRL_REG1 register */
201   LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
202   
203   /* Set new Data rate configuration */
204   tmpreg &= (uint8_t)~LIS302DL_DATARATE_400;
205   tmpreg |= DataRateValue;
206   
207   /* Write value to MEMS CTRL_REG1 regsister */
208   LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
209 }
210
211 /**
212   * @brief  Change the Full Scale of LIS302DL
213   * @param  FS_value: new full scale value. 
214   *   This parameter can be one of the following values:
215   *     @arg LIS302DL_FULLSCALE_2_3: +-2.3g
216   *     @arg LIS302DL_FULLSCALE_9_2: +-9.2g   
217   * @retval None
218   */
219 void LIS302DL_FullScaleCmd(uint8_t FS_value)
220 {
221   uint8_t tmpreg;
222   
223   /* Read CTRL_REG1 register */
224   LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
225   
226   /* Set new full scale configuration */
227   tmpreg &= (uint8_t)~LIS302DL_FULLSCALE_9_2;
228   tmpreg |= FS_value;
229   
230   /* Write value to MEMS CTRL_REG1 regsister */
231   LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1);
232 }
233
234 /**
235   * @brief  Reboot memory content of LIS302DL
236   * @param  None
237   * @retval None
238   */
239 void LIS302DL_RebootCmd(void)
240 {
241   uint8_t tmpreg;
242   /* Read CTRL_REG2 register */
243   LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG2_ADDR, 1);
244   
245   /* Enable or Disable the reboot memory */
246   tmpreg |= LIS302DL_BOOT_REBOOTMEMORY;
247   
248   /* Write value to MEMS CTRL_REG2 regsister */
249   LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG2_ADDR, 1);
250 }
251
252 /**
253   * @brief  Writes one byte to the LIS302DL.
254   * @param  pBuffer : pointer to the buffer  containing the data to be written to the LIS302DL.
255   * @param  WriteAddr : LIS302DL's internal address to write to.
256   * @param  NumByteToWrite: Number of bytes to write.
257   * @retval None
258   */
259 void LIS302DL_Write(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite)
260 {
261   /* Configure the MS bit: 
262        - When 0, the address will remain unchanged in multiple read/write commands.
263        - When 1, the address will be auto incremented in multiple read/write commands.
264   */
265   if(NumByteToWrite > 0x01)
266   {
267     WriteAddr |= (uint8_t)MULTIPLEBYTE_CMD;
268   }
269   /* Set chip select Low at the start of the transmission */
270   LIS302DL_CS_LOW();
271   
272   /* Send the Address of the indexed register */
273   LIS302DL_SendByte(WriteAddr);
274   /* Send the data that will be written into the device (MSB First) */
275   while(NumByteToWrite >= 0x01)
276   {
277     LIS302DL_SendByte(*pBuffer);
278     NumByteToWrite--;
279     pBuffer++;
280   }
281   
282   /* Set chip select High at the end of the transmission */ 
283   LIS302DL_CS_HIGH();
284 }
285
286 /**
287   * @brief  Reads a block of data from the LIS302DL.
288   * @param  pBuffer : pointer to the buffer that receives the data read from the LIS302DL.
289   * @param  ReadAddr : LIS302DL's internal address to read from.
290   * @param  NumByteToRead : number of bytes to read from the LIS302DL.
291   * @retval None
292   */
293 void LIS302DL_Read(uint8_t* pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead)
294 {  
295   if(NumByteToRead > 0x01)
296   {
297     ReadAddr |= (uint8_t)(READWRITE_CMD | MULTIPLEBYTE_CMD);
298   }
299   else
300   {
301     ReadAddr |= (uint8_t)READWRITE_CMD;
302   }
303   /* Set chip select Low at the start of the transmission */
304   LIS302DL_CS_LOW();
305   
306   /* Send the Address of the indexed register */
307   LIS302DL_SendByte(ReadAddr);
308   
309   /* Receive the data that will be read from the device (MSB First) */
310   while(NumByteToRead > 0x00)
311   {
312     /* Send dummy byte (0x00) to generate the SPI clock to LIS302DL (Slave device) */
313     *pBuffer = LIS302DL_SendByte(DUMMY_BYTE);
314     NumByteToRead--;
315     pBuffer++;
316   }
317   
318   /* Set chip select High at the end of the transmission */ 
319   LIS302DL_CS_HIGH();
320 }
321
322 /**
323   * @brief  Read LIS302DL output register, and calculate the acceleration 
324   *         ACC[mg]=SENSITIVITY* (out_h*256+out_l)/16 (12 bit rappresentation)
325   * @param  s16 buffer to store data
326   * @retval None
327   */
328 void LIS302DL_ReadACC(int32_t* out)
329 {
330   uint8_t buffer[6];
331   uint8_t crtl, i = 0x00;
332    
333   LIS302DL_Read(&crtl, LIS302DL_CTRL_REG1_ADDR, 1);  
334   LIS302DL_Read(buffer, LIS302DL_OUT_X_ADDR, 6);
335   
336   switch(crtl & 0x20) 
337     {
338     /* FS bit = 0 ==> Sensitivity typical value = 18milligals/digit*/ 
339     case 0x00:
340       for(i=0; i<0x03; i++)
341       {
342         *out =(int32_t)(LIS302DL_SENSITIVITY_2_3G *  (int8_t)buffer[2*i]);
343         out++;
344       }
345       break;
346     /* FS bit = 1 ==> Sensitivity typical value = 72milligals/digit*/ 
347     case 0x20:
348       for(i=0; i<0x03; i++)
349       {
350         *out =(int32_t)(LIS302DL_SENSITIVITY_9_2G * (int8_t)buffer[2*i]);
351         out++;
352       }         
353       break;
354     default:
355       break;
356     }
357  }
358
359 /**
360   * @brief  Initializes the low level interface used to drive the LIS302DL
361   * @param  None
362   * @retval None
363   */
364 static void LIS302DL_LowLevel_Init(void)
365 {
366   GPIO_InitTypeDef GPIO_InitStructure;
367   SPI_InitTypeDef  SPI_InitStructure;
368
369   /* Enable the SPI periph */
370   RCC_APB2PeriphClockCmd(LIS302DL_SPI_CLK, ENABLE);
371
372   /* Enable SCK, MOSI and MISO GPIO clocks */
373   RCC_AHB1PeriphClockCmd(LIS302DL_SPI_SCK_GPIO_CLK | LIS302DL_SPI_MISO_GPIO_CLK | LIS302DL_SPI_MOSI_GPIO_CLK, ENABLE);
374
375   /* Enable CS  GPIO clock */
376   RCC_AHB1PeriphClockCmd(LIS302DL_SPI_CS_GPIO_CLK, ENABLE);
377   
378   /* Enable INT1 GPIO clock */
379   RCC_AHB1PeriphClockCmd(LIS302DL_SPI_INT1_GPIO_CLK, ENABLE);
380   
381   /* Enable INT2 GPIO clock */
382   RCC_AHB1PeriphClockCmd(LIS302DL_SPI_INT2_GPIO_CLK, ENABLE);
383
384   GPIO_PinAFConfig(LIS302DL_SPI_SCK_GPIO_PORT, LIS302DL_SPI_SCK_SOURCE, LIS302DL_SPI_SCK_AF);
385   GPIO_PinAFConfig(LIS302DL_SPI_MISO_GPIO_PORT, LIS302DL_SPI_MISO_SOURCE, LIS302DL_SPI_MISO_AF);
386   GPIO_PinAFConfig(LIS302DL_SPI_MOSI_GPIO_PORT, LIS302DL_SPI_MOSI_SOURCE, LIS302DL_SPI_MOSI_AF);
387
388   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
389   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
390   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
391   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
392
393   /* SPI SCK pin configuration */
394   GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_SCK_PIN;
395   GPIO_Init(LIS302DL_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
396
397   /* SPI  MOSI pin configuration */
398   GPIO_InitStructure.GPIO_Pin =  LIS302DL_SPI_MOSI_PIN;
399   GPIO_Init(LIS302DL_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
400
401   /* SPI MISO pin configuration */
402   GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_MISO_PIN;
403   GPIO_Init(LIS302DL_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
404
405   /* SPI configuration -------------------------------------------------------*/
406   SPI_I2S_DeInit(LIS302DL_SPI);
407   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
408   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
409   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
410   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
411   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
412   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
413   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
414   SPI_InitStructure.SPI_CRCPolynomial = 7;
415   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
416   SPI_Init(LIS302DL_SPI, &SPI_InitStructure);
417
418   /* Enable SPI1  */
419   SPI_Cmd(LIS302DL_SPI, ENABLE);
420
421   /* Configure GPIO PIN for Lis Chip select */
422   GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_CS_PIN;
423   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
424   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
425   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
426   GPIO_Init(LIS302DL_SPI_CS_GPIO_PORT, &GPIO_InitStructure);
427
428   /* Deselect : Chip Select high */
429   GPIO_SetBits(LIS302DL_SPI_CS_GPIO_PORT, LIS302DL_SPI_CS_PIN);
430   
431   /* Configure GPIO PINs to detect Interrupts */
432   GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_INT1_PIN;
433   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
434   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
435   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
436   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
437   GPIO_Init(LIS302DL_SPI_INT1_GPIO_PORT, &GPIO_InitStructure);
438   
439   GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_INT2_PIN;
440   GPIO_Init(LIS302DL_SPI_INT2_GPIO_PORT, &GPIO_InitStructure);
441 }
442
443 /**
444   * @brief  Sends a Byte through the SPI interface and return the Byte received 
445   *         from the SPI bus.
446   * @param  Byte : Byte send.
447   * @retval The received byte value
448   */
449 static uint8_t LIS302DL_SendByte(uint8_t byte)
450 {
451   /* Loop while DR register in not emplty */
452   LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT;
453   while (SPI_I2S_GetFlagStatus(LIS302DL_SPI, SPI_I2S_FLAG_TXE) == RESET)
454   {
455     if((LIS302DLTimeout--) == 0) return LIS302DL_TIMEOUT_UserCallback();
456   }
457   
458   /* Send a Byte through the SPI peripheral */
459   SPI_I2S_SendData(LIS302DL_SPI, byte);
460   
461   /* Wait to receive a Byte */
462   LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT;
463   while (SPI_I2S_GetFlagStatus(LIS302DL_SPI, SPI_I2S_FLAG_RXNE) == RESET)
464   {
465     if((LIS302DLTimeout--) == 0) return LIS302DL_TIMEOUT_UserCallback();
466   }
467   
468   /* Return the Byte read from the SPI bus */
469   return (uint8_t)SPI_I2S_ReceiveData(LIS302DL_SPI);
470 }
471
472 #ifdef USE_DEFAULT_TIMEOUT_CALLBACK
473 /**
474   * @brief  Basic management of the timeout situation.
475   * @param  None.
476   * @retval None.
477   */
478 uint32_t LIS302DL_TIMEOUT_UserCallback(void)
479 {
480   /* Block communication and all processes */
481   while (1)
482   {   
483   }
484 }
485 #endif /* USE_DEFAULT_TIMEOUT_CALLBACK */
486
487 /**
488   * @}
489   */ 
490
491 /**
492   * @}
493   */ 
494   
495 /**
496   * @}
497   */ 
498
499 /**
500   * @}
501   */ 
502   
503
504 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/