From 4856df1aad69f5834b1a5e5ef32c0f8fb7cdec45 Mon Sep 17 00:00:00 2001 From: jnosky Date: Sat, 12 Nov 2011 16:17:03 -0500 Subject: [PATCH] Added STM32F4-Discovery utilities --- .../STM32F4-Discovery/Release_Notes.html | 151 ++ .../STM32F4-Discovery/stm32f4_discovery.c | 257 +++ .../STM32F4-Discovery/stm32f4_discovery.h | 158 ++ .../stm32f4_discovery_audio_codec.c | 1651 +++++++++++++++++ .../stm32f4_discovery_audio_codec.h | 304 +++ .../stm32f4_discovery_lis302dl.c | 504 +++++ .../stm32f4_discovery_lis302dl.h | 772 ++++++++ 7 files changed, 3797 insertions(+) create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/Release_Notes.html create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.c create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.h create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.c create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.h create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c create mode 100644 example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.h diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/Release_Notes.html b/example/stm32f4/Utilities/STM32F4-Discovery/Release_Notes.html new file mode 100644 index 0000000..7b270b4 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/Release_Notes.html @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + Release Notes for STM32F4-Discovery Board Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F4-Discovery Board Drivers

+

Copyright +2011 STMicroelectronics

+

+
+

 

+ + + + + + +
+

Contents

+
    +
  1. STM32F4-Discovery Board Drivers update History
  2. +
  3. License
  4. +
+ + +

STM32F4-Discovery Board Drivers update History

For more information on the STM32F4-Discovery board visit www.st.com/stm32f4-discovery.

V1.0.0 / 19-September-2011

+

Main +Changes

+ +
  • First official version of the STM32F4-Discovery Board Drivers

License

+

The +enclosed firmware and all the related documentation are not covered by +a License Agreement, if you need such License you can contact your +local STMicroelectronics office.

+ + THE +PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS +WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO +SAVE TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR +ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY +CLAIMS ARISING FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY +CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH +THEIR PRODUCTS. + +
+
+

For +complete documentation on STMicroelectronics Microcontrollers visit www.st.com

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.c b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.c new file mode 100644 index 0000000..ff0d697 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.c @@ -0,0 +1,257 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file provides set of firmware functions to manage Leds and + * push-button available on STM32F4-Discovery Kit from STMicroelectronics. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4_discovery.h" + +//ADDED BY ME!!!!!!!!!!!!!!!!!!!! +#include "stm32f4xx_conf.h" + + +/** @addtogroup Utilities + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL + * @brief This file provides set of firmware functions to manage Leds and push-button + * available on STM32F4-Discovery Kit from STMicroelectronics. + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_Defines + * @{ + */ +/** + * @} + */ + + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_Variables + * @{ + */ +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED4_GPIO_PORT, LED3_GPIO_PORT, LED5_GPIO_PORT, + LED6_GPIO_PORT}; +const uint16_t GPIO_PIN[LEDn] = {LED4_PIN, LED3_PIN, LED5_PIN, + LED6_PIN}; +const uint32_t GPIO_CLK[LEDn] = {LED4_GPIO_CLK, LED3_GPIO_CLK, LED5_GPIO_CLK, + LED6_GPIO_CLK}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {USER_BUTTON_GPIO_PORT }; + +const uint16_t BUTTON_PIN[BUTTONn] = {USER_BUTTON_PIN }; + +const uint32_t BUTTON_CLK[BUTTONn] = {USER_BUTTON_GPIO_CLK }; + +const uint16_t BUTTON_EXTI_LINE[BUTTONn] = {USER_BUTTON_EXTI_LINE }; + +const uint8_t BUTTON_PORT_SOURCE[BUTTONn] = {USER_BUTTON_EXTI_PORT_SOURCE}; + +const uint8_t BUTTON_PIN_SOURCE[BUTTONn] = {USER_BUTTON_EXTI_PIN_SOURCE }; +const uint8_t BUTTON_IRQn[BUTTONn] = {USER_BUTTON_EXTI_IRQn }; + +NVIC_InitTypeDef NVIC_InitStructure; + +/** + * @} + */ + + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Private_Functions + * @{ + */ + +/** + * @brief Configures LED GPIO. + * @param Led: Specifies the Led to be configured. + * This parameter can be one of following parameters: + * @arg LED4 + * @arg LED3 + * @arg LED5 + * @arg LED6 + * @retval None + */ +void STM_EVAL_LEDInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable the GPIO_LED Clock */ + RCC_AHB1PeriphClockCmd(GPIO_CLK[Led], ENABLE); + + /* Configure the GPIO_LED pin */ + GPIO_InitStructure.GPIO_Pin = GPIO_PIN[Led]; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIO_PORT[Led], &GPIO_InitStructure); +} + +/** + * @brief Turns selected LED On. + * @param Led: Specifies the Led to be set on. + * This parameter can be one of following parameters: + * @arg LED4 + * @arg LED3 + * @arg LED5 + * @arg LED6 + * @retval None + */ +void STM_EVAL_LEDOn(Led_TypeDef Led) +{ + GPIO_PORT[Led]->BSRRL = GPIO_PIN[Led]; +} + +/** + * @brief Turns selected LED Off. + * @param Led: Specifies the Led to be set off. + * This parameter can be one of following parameters: + * @arg LED4 + * @arg LED3 + * @arg LED5 + * @arg LED6 + * @retval None + */ +void STM_EVAL_LEDOff(Led_TypeDef Led) +{ + GPIO_PORT[Led]->BSRRH = GPIO_PIN[Led]; +} + +/** + * @brief Toggles the selected LED. + * @param Led: Specifies the Led to be toggled. + * This parameter can be one of following parameters: + * @arg LED4 + * @arg LED3 + * @arg LED5 + * @arg LED6 + * @retval None + */ +void STM_EVAL_LEDToggle(Led_TypeDef Led) +{ + GPIO_PORT[Led]->ODR ^= GPIO_PIN[Led]; +} + +/** + * @brief Configures Button GPIO and EXTI Line. + * @param Button: Specifies the Button to be configured. + * This parameter should be: BUTTON_USER + * @param Button_Mode: Specifies Button mode. + * This parameter can be one of following parameters: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line with interrupt + * generation capability + * @retval None + */ +void STM_EVAL_PBInit(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode) +{ + GPIO_InitTypeDef GPIO_InitStructure; + EXTI_InitTypeDef EXTI_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* Enable the BUTTON Clock */ + RCC_AHB1PeriphClockCmd(BUTTON_CLK[Button], ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); + + /* Configure Button pin as input */ + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_InitStructure.GPIO_Pin = BUTTON_PIN[Button]; + GPIO_Init(BUTTON_PORT[Button], &GPIO_InitStructure); + + if (Button_Mode == BUTTON_MODE_EXTI) + { + /* Connect Button EXTI Line to Button GPIO Pin */ + SYSCFG_EXTILineConfig(BUTTON_PORT_SOURCE[Button], BUTTON_PIN_SOURCE[Button]); + + /* Configure Button EXTI line */ + EXTI_InitStructure.EXTI_Line = BUTTON_EXTI_LINE[Button]; + EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; + EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; + EXTI_InitStructure.EXTI_LineCmd = ENABLE; + EXTI_Init(&EXTI_InitStructure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + NVIC_InitStructure.NVIC_IRQChannel = BUTTON_IRQn[Button]; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + + NVIC_Init(&NVIC_InitStructure); + } +} + +/** + * @brief Returns the selected Button state. + * @param Button: Specifies the Button to be checked. + * This parameter should be: BUTTON_USER + * @retval The Button GPIO pin value. + */ +uint32_t STM_EVAL_PBGetState(Button_TypeDef Button) +{ + return GPIO_ReadInputDataBit(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.h b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.h new file mode 100644 index 0000000..c6fec42 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery.h @@ -0,0 +1,158 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file contains definitions for STM32F4-Discovery Kit's Leds and + * push-button hardware resources. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4_DISCOVERY_H +#define __STM32F4_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + #include "stm32f4xx.h" + +/** @addtogroup Utilities + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Exported_Types + * @{ + */ +typedef enum +{ + LED4 = 0, + LED3 = 1, + LED5 = 2, + LED6 = 3 +} Led_TypeDef; + +typedef enum +{ + BUTTON_USER = 0, +} Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +} ButtonMode_TypeDef; +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Exported_Constants + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY_LOW_LEVEL_LED + * @{ + */ +#define LEDn 4 + +#define LED4_PIN GPIO_Pin_12 +#define LED4_GPIO_PORT GPIOD +#define LED4_GPIO_CLK RCC_AHB1Periph_GPIOD + +#define LED3_PIN GPIO_Pin_13 +#define LED3_GPIO_PORT GPIOD +#define LED3_GPIO_CLK RCC_AHB1Periph_GPIOD + +#define LED5_PIN GPIO_Pin_14 +#define LED5_GPIO_PORT GPIOD +#define LED5_GPIO_CLK RCC_AHB1Periph_GPIOD + +#define LED6_PIN GPIO_Pin_15 +#define LED6_GPIO_PORT GPIOD +#define LED6_GPIO_CLK RCC_AHB1Periph_GPIOD +/** + * @} + */ + +/** @addtogroup STM32F4_DISCOVERY_LOW_LEVEL_BUTTON + * @{ + */ +#define BUTTONn 1 + +/** + * @brief Wakeup push-button + */ +#define USER_BUTTON_PIN GPIO_Pin_0 +#define USER_BUTTON_GPIO_PORT GPIOA +#define USER_BUTTON_GPIO_CLK RCC_AHB1Periph_GPIOA +#define USER_BUTTON_EXTI_LINE EXTI_Line0 +#define USER_BUTTON_EXTI_PORT_SOURCE EXTI_PortSourceGPIOA +#define USER_BUTTON_EXTI_PIN_SOURCE EXTI_PinSource0 +#define USER_BUTTON_EXTI_IRQn EXTI0_IRQn +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Exported_Macros + * @{ + */ +/** + * @} + */ + + +/** @defgroup STM32F4_DISCOVERY_LOW_LEVEL_Exported_Functions + * @{ + */ +void STM_EVAL_LEDInit(Led_TypeDef Led); +void STM_EVAL_LEDOn(Led_TypeDef Led); +void STM_EVAL_LEDOff(Led_TypeDef Led); +void STM_EVAL_LEDToggle(Led_TypeDef Led); +void STM_EVAL_PBInit(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode); +uint32_t STM_EVAL_PBGetState(Button_TypeDef Button); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4_DISCOVERY_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.c b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.c new file mode 100644 index 0000000..0445aa5 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.c @@ -0,0 +1,1651 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery_audio_codec.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file includes the low layer driver for CS43L22 Audio Codec + * available on STM32F4-Discovery Kit. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/*============================================================================================================================== + User NOTES +1. How To use this driver: +-------------------------- + - This driver supports STM32F4xx devices on STM32F4-Discovery Kit. + + - Configure the options in file stm32f4_discovery_audio_codec.h in the section CONFIGURATION. + Refer to the sections 2 and 3 to have more details on the possible configurations. + + - Call the function EVAL_AUDIO_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_AUTO or + OUTPUT_DEVICE_BOTH) + Volume: initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000 ...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, I2S, + GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK. + if the returned value is different from 0 or the function is stuck then the communication with + the codec (try to un-plug the power or reset device in this case). + + OUTPUT_DEVICE_SPEAKER: only speaker will be set as output for the audio stream. + + OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + + OUTPUT_DEVICE_AUTO: Selection of output device is made through external switch (implemented + into the audio jack on the evaluation board). When the Headphone is connected it is used + as output. When the headphone is disconnected from the audio jack, the output is + automatically switched to Speaker. + + OUTPUT_DEVICE_BOTH: both Speaker and Headphone are used as outputs for the audio stream + at the same time. + + - Call the function EVAL_AUDIO_Play( + pBuffer: pointer to the audio data file address + Size: size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + - Call the function EVAL_AUDIO_PauseResume( + Cmd: AUDIO_PAUSE (or 0) to pause playing or AUDIO_RESUME (or + any value different from 0) to resume playing. + ) + Note. After calling EVAL_AUDIO_PauseResume() function for pause, only EVAL_AUDIO_PauseResume() should be called + for resume (it is not allowed to call EVAL_AUDIO_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + - For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named EVAL_AUDIO_XXX_CallBack() and only their prototypes are declared in + the stm32f4_discovery_audio_codec.h file. (refer to the example for more details on the callbacks implementations) + + - To Stop playing, to modify the volume level or to mute, use the functions + EVAL_AUDIO_Stop(), EVAL_AUDIO_VolumeCtl() and EVAL_AUDIO_Mute(). + + - The driver API and the callback functions are at the end of the stm32f4_discovery_audio_codec.h file. + + + Driver architecture: + -------------------- + This driver is composed of three main layers: + o High Audio Layer: consists of the function API exported in the stm32f4_discovery_audio_codec.h file + (EVAL_AUDIO_Init(), EVAL_AUDIO_Play() ...) + o Codec Control layer: consists of the functions API controlling the audio codec (CS43L22) and + included as local functions in file stm32f4_discovery_audio_codec.c (Codec_Init(), Codec_Play() ...) + o Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f4_discovery_audio_codec.c file (Audio_MAL_Init(), Audio_MAL_Play() ...) + Each set of functions (layer) may be implemented independently of the others and customized when + needed. + +2. Modes description: +--------------------- + + AUDIO_MAL_MODE_NORMAL : is suitable when the audio file is in a memory location. + + AUDIO_MAL_MODE_CIRCULAR: is suitable when the audio data are read either from a + memory location or from a device at real time (double buffer could be used). + +3. DMA interrupts description: +------------------------------ + + EVAL_AUDIO_IT_TC_ENABLE: Enable this define to use the DMA end of transfer interrupt. + then, a callback should be implemented by user to perform specific actions + when the DMA has finished the transfer. + + EVAL_AUDIO_IT_HT_ENABLE: Enable this define to use the DMA end of half transfer interrupt. + then, a callback should be implemented by user to perform specific actions + when the DMA has reached the half of the buffer transfer (generally, it is useful + to load the first half of buffer while DMA is loading from the second half). + + EVAL_AUDIO_IT_ER_ENABLE: Enable this define to manage the cases of error on DMA transfer. + +4. Known Limitations: +--------------------- + 1- When using the Speaker, if the audio file quality is not high enough, the speaker output + may produce high and uncomfortable noise level. To avoid this issue, to use speaker + output properly, try to increase audio file sampling rate (typically higher than 48KHz). + This operation will lead to larger file size. + 2- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some + user interrupt routines (in this case, interrupts could be disabled just before the start of + communication then re-enabled when it is over). Note that this communication is only done at + the configuration phase (EVAL_AUDIO_Init() or EVAL_AUDIO_Stop()) and when Volume control modification is + performed (EVAL_AUDIO_VolumeCtl() or EVAL_AUDIO_Mute()). When the audio data is played, no communication is + required with the audio codec. + 3- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 4- Mono audio streaming is not supported (in order to play mono audio streams, each data should be sent twice + on the I2S or should be duplicated on the source buffer. Or convert the stream in stereo before playing). + 5- Supports only 16-bit audio data size. +===============================================================================================================================*/ + + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4_discovery_audio_codec.h" +//ADDED BY ME!!!!!!!!!!!!!!!!!!!! +#include "stm32f4xx_conf.h" + +/** @addtogroup Utilities + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY_AUDIO_CODEC + * @brief This file includes the low layer driver for CS43L22 Audio Codec + * available on STM32F4-Discovery Kit. + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Defines + * @{ + */ + +/* Mask for the bit EN of the I2S CFGR register */ +#define I2S_ENABLE_MASK 0x0400 + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY 0x4FFF + +/* Codec audio Standards */ +#ifdef I2S_STANDARD_PHILLIPS + #define CODEC_STANDARD 0x04 + #define I2S_STANDARD I2S_Standard_Phillips +#elif defined(I2S_STANDARD_MSB) + #define CODEC_STANDARD 0x00 + #define I2S_STANDARD I2S_Standard_MSB +#elif defined(I2S_STANDARD_LSB) + #define CODEC_STANDARD 0x08 + #define I2S_STANDARD I2S_Standard_LSB +#else + #error "Error: No audio communication standard selected !" +#endif /* I2S_STANDARD */ + +/* The 7 bits Codec address (sent through I2C interface) */ +#define CODEC_ADDRESS 0x94 /* b00100111 */ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Variables + * @{ + */ +/* This structure is declared global because it is handled by two different functions */ +static DMA_InitTypeDef DMA_InitStructure; +DMA_InitTypeDef AUDIO_MAL_DMA_InitStructure; + +uint32_t AudioTotalSize = 0xFFFF; /* This variable holds the total size of the audio file */ +uint32_t AudioRemSize = 0xFFFF; /* This variable holds the remaining data in audio file */ +uint16_t *CurrentPos; /* This variable holds the current position of audio pointer */ + +__IO uint32_t CODECTimeout = CODEC_LONG_TIMEOUT; +__IO uint8_t OutputDev = 0; + + +__IO uint32_t CurrAudioInterface = AUDIO_INTERFACE_I2S; //AUDIO_INTERFACE_DAC +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Function_Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Private_Functions + * @{ + */ +static void Audio_MAL_IRQHandler(void); +/*----------------------------------- + Audio Codec functions + ------------------------------------------*/ +/* High Layer codec functions */ +static uint32_t Codec_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +static uint32_t Codec_DeInit(void); +static uint32_t Codec_Play(void); +static uint32_t Codec_PauseResume(uint32_t Cmd); +static uint32_t Codec_Stop(uint32_t Cmd); +static uint32_t Codec_VolumeCtrl(uint8_t Volume); +static uint32_t Codec_Mute(uint32_t Cmd); +/* Low layer codec functions */ +static void Codec_CtrlInterface_Init(void); +static void Codec_CtrlInterface_DeInit(void); +static void Codec_AudioInterface_Init(uint32_t AudioFreq); +static void Codec_AudioInterface_DeInit(void); +static void Codec_Reset(void); +static uint32_t Codec_WriteRegister(uint8_t RegisterAddr, uint8_t RegisterValue); +static uint32_t Codec_ReadRegister(uint8_t RegisterAddr); +static void Codec_GPIO_Init(void); +static void Codec_GPIO_DeInit(void); +static void Delay(__IO uint32_t nCount); +/*----------------------------------------------------------------------------*/ + +/*----------------------------------- + MAL (Media Access Layer) functions + ------------------------------------------*/ +/* Peripherals configuration functions */ +static void Audio_MAL_Init(void); +static void Audio_MAL_DeInit(void); +static void Audio_MAL_Play(uint32_t Addr, uint32_t Size); +static void Audio_MAL_PauseResume(uint32_t Cmd, uint32_t Addr); +static void Audio_MAL_Stop(void); +/*----------------------------------------------------------------------------*/ + + /* DMA Stream definitions */ + uint32_t AUDIO_MAL_DMA_CLOCK = AUDIO_I2S_DMA_CLOCK; + DMA_Stream_TypeDef * AUDIO_MAL_DMA_STREAM = AUDIO_I2S_DMA_STREAM ; + uint32_t AUDIO_MAL_DMA_DREG = AUDIO_I2S_DMA_DREG; + uint32_t AUDIO_MAL_DMA_CHANNEL = AUDIO_I2S_DMA_CHANNEL; + uint32_t AUDIO_MAL_DMA_IRQ = AUDIO_I2S_DMA_IRQ ; + uint32_t AUDIO_MAL_DMA_FLAG_TC = AUDIO_I2S_DMA_FLAG_TC; + uint32_t AUDIO_MAL_DMA_FLAG_HT = AUDIO_I2S_DMA_FLAG_HT; + uint32_t AUDIO_MAL_DMA_FLAG_FE = AUDIO_I2S_DMA_FLAG_FE; + uint32_t AUDIO_MAL_DMA_FLAG_TE = AUDIO_I2S_DMA_FLAG_TE; + uint32_t AUDIO_MAL_DMA_FLAG_DME = AUDIO_I2S_DMA_FLAG_DME; + +/** + * @brief Set the current audio interface (I2S or DAC). + * @param Interface: AUDIO_INTERFACE_I2S or AUDIO_INTERFACE_DAC + * @retval None + */ +void EVAL_AUDIO_SetAudioInterface(uint32_t Interface) +{ + CurrAudioInterface = Interface; + + if (CurrAudioInterface == AUDIO_INTERFACE_I2S) + { + /* DMA Stream definitions */ + AUDIO_MAL_DMA_CLOCK = AUDIO_I2S_DMA_CLOCK; + AUDIO_MAL_DMA_STREAM = AUDIO_I2S_DMA_STREAM; + AUDIO_MAL_DMA_DREG = AUDIO_I2S_DMA_DREG; + AUDIO_MAL_DMA_CHANNEL = AUDIO_I2S_DMA_CHANNEL; + AUDIO_MAL_DMA_IRQ = AUDIO_I2S_DMA_IRQ ; + AUDIO_MAL_DMA_FLAG_TC = AUDIO_I2S_DMA_FLAG_TC; + AUDIO_MAL_DMA_FLAG_HT = AUDIO_I2S_DMA_FLAG_HT; + AUDIO_MAL_DMA_FLAG_FE = AUDIO_I2S_DMA_FLAG_FE; + AUDIO_MAL_DMA_FLAG_TE = AUDIO_I2S_DMA_FLAG_TE; + AUDIO_MAL_DMA_FLAG_DME = AUDIO_I2S_DMA_FLAG_DME; + } + else if (Interface == AUDIO_INTERFACE_DAC) + { + /* DMA Stream definitions */ + AUDIO_MAL_DMA_CLOCK = AUDIO_DAC_DMA_CLOCK; + AUDIO_MAL_DMA_STREAM = AUDIO_DAC_DMA_STREAM; + AUDIO_MAL_DMA_DREG = AUDIO_DAC_DMA_DREG; + AUDIO_MAL_DMA_CHANNEL = AUDIO_DAC_DMA_CHANNEL; + AUDIO_MAL_DMA_IRQ = AUDIO_DAC_DMA_IRQ ; + AUDIO_MAL_DMA_FLAG_TC = AUDIO_DAC_DMA_FLAG_TC; + AUDIO_MAL_DMA_FLAG_HT = AUDIO_DAC_DMA_FLAG_HT; + AUDIO_MAL_DMA_FLAG_FE = AUDIO_DAC_DMA_FLAG_FE; + AUDIO_MAL_DMA_FLAG_TE = AUDIO_DAC_DMA_FLAG_TE; + AUDIO_MAL_DMA_FLAG_DME = AUDIO_DAC_DMA_FLAG_DME; + } +} + +/** + * @brief Configure the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO . + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + /* Perform low layer Codec initialization */ + if (Codec_Init(OutputDevice, VOLUME_CONVERT(Volume), AudioFreq) != 0) + { + return 1; + } + else + { + /* I2S data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to I2S peripheral */ + Audio_MAL_Init(); + + /* Return 0 when all operations are OK */ + return 0; + } +} + +/** + * @brief Deinitializes all the resources used by the codec (those initialized + * by EVAL_AUDIO_Init() function). + * @param None + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_DeInit(void) +{ + /* DeInitialize the Media layer */ + Audio_MAL_DeInit(); + + /* DeInitialize Codec */ + Codec_DeInit(); + + return 0; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Set the total number of data to be played (count in half-word) */ + AudioTotalSize = Size/2; + + /* Call the audio Codec Play function */ + Codec_Play(); + + /* Update the Media layer and enable it for play */ + Audio_MAL_Play((uint32_t)pBuffer, (uint32_t)(DMA_MAX(AudioTotalSize / 2))); + + /* Update the remaining number of data to be played */ + AudioRemSize = (Size/2) - DMA_MAX(AudioTotalSize); + + /* Update the current audio pointer position */ + CurrentPos = pBuffer + DMA_MAX(AudioTotalSize); + + return 0; +} + +/** + * @brief This function Pauses or Resumes the audio file stream. In case + * of using DMA, the DMA Pause feature is used. In all cases the I2S + * peripheral is disabled. + * + * @WARNING When calling EVAL_AUDIO_PauseResume() function for pause, only + * this function should be called for resume (use of EVAL_AUDIO_Play() + * function for resume could lead to unexpected behavior). + * + * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different + * from 0) to resume. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_PauseResume(uint32_t Cmd) +{ + /* Call the Audio Codec Pause/Resume function */ + if (Codec_PauseResume(Cmd) != 0) + { + return 1; + } + else + { + /* Call the Media layer pause/resume function */ + Audio_MAL_PauseResume(Cmd, 0); + + /* Return 0 if all operations are OK */ + return 0; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_Stop(uint32_t Option) +{ + /* Call Audio Codec Stop function */ + if (Codec_Stop(Option) != 0) + { + return 1; + } + else + { + /* Call Media layer Stop function */ + Audio_MAL_Stop(); + + /* Update the remaining data number */ + AudioRemSize = AudioTotalSize; + + /* Return 0 when all operations are correctly done */ + return 0; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_VolumeCtl(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + return (Codec_VolumeCtrl(VOLUME_CONVERT(Volume))); +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Command: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t EVAL_AUDIO_Mute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + return (Codec_Mute(Cmd)); +} + +/** + * @brief This function handles main Media layer interrupt. + * @param None + * @retval 0 if correct communication, else wrong communication + */ +static void Audio_MAL_IRQHandler(void) +{ +#ifndef AUDIO_MAL_MODE_NORMAL + uint16_t *pAddr = (uint16_t *)CurrentPos; + uint32_t Size = AudioRemSize; +#endif /* AUDIO_MAL_MODE_NORMAL */ + +#ifdef AUDIO_MAL_DMA_IT_TC_EN + /* Transfer complete interrupt */ + if (DMA_GetFlagStatus(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC) != RESET) + { + #ifdef AUDIO_MAL_MODE_NORMAL + /* Check if the end of file has been reached */ + if (AudioRemSize > 0) + { + /* Wait the DMA Stream to be effectively disabled */ + while (DMA_GetCmdStatus(AUDIO_MAL_DMA_STREAM) != DISABLE) + {} + + /* Clear the Interrupt flag */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC); + + /* Re-Configure the buffer address and size */ + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) CurrentPos; + DMA_InitStructure.DMA_BufferSize = (uint32_t) (DMA_MAX(AudioRemSize)); + + /* Configure the DMA Stream with the new parameters */ + DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_InitStructure); + + /* Enable the I2S DMA Stream*/ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, ENABLE); + + /* Update the current pointer position */ + CurrentPos += DMA_MAX(AudioRemSize); + + /* Update the remaining number of data to be played */ + AudioRemSize -= DMA_MAX(AudioRemSize); + } + else + { + /* Disable the I2S DMA Stream*/ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + + /* Clear the Interrupt flag */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC); + + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f4_discovery_audio_codec.h) */ + EVAL_AUDIO_TransferComplete_CallBack((uint32_t)CurrentPos, 0); + } + + #elif defined(AUDIO_MAL_MODE_CIRCULAR) + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f4_discovery_audio_codec.h) */ + EVAL_AUDIO_TransferComplete_CallBack(pAddr, Size); + + /* Clear the Interrupt flag */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC); + #endif /* AUDIO_MAL_MODE_NORMAL */ + } +#endif /* AUDIO_MAL_DMA_IT_TC_EN */ + +#ifdef AUDIO_MAL_DMA_IT_HT_EN + /* Half Transfer complete interrupt */ + if (DMA_GetFlagStatus(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_HT) != RESET) + { + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f4_discovery_audio_codec.h) */ + EVAL_AUDIO_HalfTransfer_CallBack((uint32_t)pAddr, Size); + + /* Clear the Interrupt flag */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_HT); + } +#endif /* AUDIO_MAL_DMA_IT_HT_EN */ + +#ifdef AUDIO_MAL_DMA_IT_TE_EN + /* FIFO Error interrupt */ + if ((DMA_GetFlagStatus(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TE) != RESET) || \ + (DMA_GetFlagStatus(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_FE) != RESET) || \ + (DMA_GetFlagStatus(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_DME) != RESET)) + + { + /* Manage the error generated on DMA FIFO: This function + should be coded by user (its prototype is already declared in stm32f4_discovery_audio_codec.h) */ + EVAL_AUDIO_Error_CallBack((uint32_t*)&pAddr); + + /* Clear the Interrupt flag */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TE | AUDIO_MAL_DMA_FLAG_FE | \ + AUDIO_MAL_DMA_FLAG_DME); + } +#endif /* AUDIO_MAL_DMA_IT_TE_EN */ +} + +/** + * @brief This function handles main I2S interrupt. + * @param None + * @retval 0 if correct communication, else wrong communication + */ +void Audio_MAL_I2S_IRQHandler(void) +{ + Audio_MAL_IRQHandler(); +} + +/** + * @brief This function handles main DAC interrupt. + * @param None + * @retval 0 if correct communication, else wrong communication + */ +void Audio_MAL_DAC_IRQHandler(void) +{ + Audio_MAL_IRQHandler(); +} + +/** + * @brief I2S interrupt management + * @param None + * @retval None + */ +void Audio_I2S_IRQHandler(void) +{ + /* Check on the I2S TXE flag */ + if (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) != RESET) + { + if (CurrAudioInterface == AUDIO_INTERFACE_DAC) + { + /* Wirte data to the DAC interface */ + DAC_SetChannel1Data(DAC_Align_12b_L, EVAL_AUDIO_GetSampleCallBack()); + } + + /* Send dummy data on I2S to avoid the underrun condition */ + SPI_I2S_SendData(CODEC_I2S, EVAL_AUDIO_GetSampleCallBack()); + } +} +/*======================== + + CS43L22 Audio Codec Control Functions + ==============================*/ +/** + * @brief Initializes the audio codec and all related interfaces (control + * interface: I2C and audio interface: I2S) + * @param OutputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO . + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint32_t counter = 0; + + /* Configure the Codec related IOs */ + Codec_GPIO_Init(); + + /* Reset the Codec Registers */ + Codec_Reset(); + + /* Initialize the Control interface of the Audio Codec */ + Codec_CtrlInterface_Init(); + + /* Keep Codec powered OFF */ + counter += Codec_WriteRegister(0x02, 0x01); + + counter += Codec_WriteRegister(0x04, 0xAF); /* SPK always OFF & HP always ON */ + OutputDev = 0xAF; + + /* Clock configuration: Auto detection */ + counter += Codec_WriteRegister(0x05, 0x81); + + /* Set the Slave Mode and the audio Standard */ + counter += Codec_WriteRegister(0x06, CODEC_STANDARD); + + /* Set the Master volume */ + Codec_VolumeCtrl(Volume); + + if (CurrAudioInterface == AUDIO_INTERFACE_DAC) + { + /* Enable the PassThrough on AIN1A and AIN1B */ + counter += Codec_WriteRegister(0x08, 0x01); + counter += Codec_WriteRegister(0x09, 0x01); + + /* Route the analog input to the HP line */ + counter += Codec_WriteRegister(0x0E, 0xC0); + + /* Set the Passthough volume */ + counter += Codec_WriteRegister(0x14, 0x00); + counter += Codec_WriteRegister(0x15, 0x00); + } + + /* Power on the Codec */ + counter += Codec_WriteRegister(0x02, 0x9E); + + /* Additional configuration for the CODEC. These configurations are done to reduce + the time needed for the Codec to power off. If these configurations are removed, + then a long delay should be added between powering off the Codec and switching + off the I2S peripheral MCLK clock (which is the operating clock for Codec). + If this delay is not inserted, then the codec will not shut down properly and + it results in high noise after shut down. */ + + /* Disable the analog soft ramp */ + counter += Codec_WriteRegister(0x0A, 0x00); + if (CurrAudioInterface != AUDIO_INTERFACE_DAC) + { + /* Disable the digital soft ramp */ + counter += Codec_WriteRegister(0x0E, 0x04); + } + /* Disable the limiter attack level */ + counter += Codec_WriteRegister(0x27, 0x00); + /* Adjust Bass and Treble levels */ + counter += Codec_WriteRegister(0x1F, 0x0F); + /* Adjust PCM volume level */ + counter += Codec_WriteRegister(0x1A, 0x0A); + counter += Codec_WriteRegister(0x1B, 0x0A); + + /* Configure the I2S peripheral */ + Codec_AudioInterface_Init(AudioFreq); + + /* Return communication control value */ + return counter; +} + +/** + * @brief Restore the audio codec state to default state and free all used + * resources. + * @param None + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_DeInit(void) +{ + uint32_t counter = 0; + + /* Reset the Codec Registers */ + Codec_Reset(); + + /* Keep Codec powered OFF */ + counter += Codec_WriteRegister(0x02, 0x01); + + /* Deinitialize all use GPIOs */ + Codec_GPIO_DeInit(); + + /* Disable the Codec control interface */ + Codec_CtrlInterface_DeInit(); + + /* Deinitialize the Codec audio interface (I2S) */ + Codec_AudioInterface_DeInit(); + + /* Return communication control value */ + return counter; +} + +/** + * @brief Start the audio Codec play feature. + * @note For this codec no Play options are required. + * @param None + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_Play(void) +{ + /* + No actions required on Codec level for play command + */ + + /* Return communication control value */ + return 0; +} + +/** + * @brief Pauses and resumes playing on the audio codec. + * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different + * from 0) to resume. + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_PauseResume(uint32_t Cmd) +{ + uint32_t counter = 0; + + /* Pause the audio file playing */ + if (Cmd == AUDIO_PAUSE) + { + /* Mute the output first */ + counter += Codec_Mute(AUDIO_MUTE_ON); + + /* Put the Codec in Power save mode */ + counter += Codec_WriteRegister(0x02, 0x01); + } + else /* AUDIO_RESUME */ + { + /* Unmute the output first */ + counter += Codec_Mute(AUDIO_MUTE_OFF); + + counter += Codec_WriteRegister(0x04, OutputDev); + + /* Exit the Power save mode */ + counter += Codec_WriteRegister(0x02, 0x9E); + } + + return counter; +} + +/** + * @brief Stops audio Codec playing. It powers down the codec. + * @param CodecPdwnMode: selects the power down mode. + * - CODEC_PDWN_SW: only mutes the audio codec. When resuming from this + * mode the codec keeps the previous initialization + * (no need to re-Initialize the codec registers). + * - CODEC_PDWN_HW: Physically power down the codec. When resuming from this + * mode, the codec is set to default configuration + * (user should re-Initialize the codec in order to + * play again the audio stream). + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_Stop(uint32_t CodecPdwnMode) +{ + uint32_t counter = 0; + + /* Mute the output first */ + Codec_Mute(AUDIO_MUTE_ON); + + if (CodecPdwnMode == CODEC_PDWN_SW) + { + /* Power down the DAC and the speaker (PMDAC and PMSPK bits)*/ + counter += Codec_WriteRegister(0x02, 0x9F); + } + else /* CODEC_PDWN_HW */ + { + /* Power down the DAC components */ + counter += Codec_WriteRegister(0x02, 0x9F); + + /* Wait at least 100us */ + Delay(0xFFF); + + /* Reset The pin */ + GPIO_WriteBit(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, Bit_RESET); + } + + return counter; +} + +/** + * @brief Sets higher or lower the codec volume level. + * @param Volume: a byte value from 0 to 255 (refer to codec registers + * description for more details). + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_VolumeCtrl(uint8_t Volume) +{ + uint32_t counter = 0; + + if (Volume > 0xE6) + { + /* Set the Master volume */ + counter += Codec_WriteRegister(0x20, Volume - 0xE7); + counter += Codec_WriteRegister(0x21, Volume - 0xE7); + } + else + { + /* Set the Master volume */ + counter += Codec_WriteRegister(0x20, Volume + 0x19); + counter += Codec_WriteRegister(0x21, Volume + 0x19); + } + + return counter; +} + +/** + * @brief Enables or disables the mute feature on the audio codec. + * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the + * mute mode. + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_Mute(uint32_t Cmd) +{ + uint32_t counter = 0; + + /* Set the Mute mode */ + if (Cmd == AUDIO_MUTE_ON) + { + counter += Codec_WriteRegister(0x04, 0xFF); + } + else /* AUDIO_MUTE_OFF Disable the Mute */ + { + counter += Codec_WriteRegister(0x04, OutputDev); + } + + return counter; +} + +/** + * @brief Resets the audio codec. It restores the default configuration of the + * codec (this function shall be called before initializing the codec). + * @note This function calls an external driver function: The IO Expander driver. + * @param None + * @retval None + */ +static void Codec_Reset(void) +{ + /* Power Down the codec */ + GPIO_WriteBit(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, Bit_RESET); + + /* wait for a delay to insure registers erasing */ + Delay(CODEC_RESET_DELAY); + + /* Power on the codec */ + GPIO_WriteBit(AUDIO_RESET_GPIO, AUDIO_RESET_PIN, Bit_SET); +} + +/** + * @brief Writes a Byte to a given register into the audio codec through the + control interface (I2C) + * @param RegisterAddr: The address (location) of the register to be written. + * @param RegisterValue: the Byte value to be written into destination register. + * @retval 0 if correct communication, else wrong communication + */ +static uint32_t Codec_WriteRegister(uint8_t RegisterAddr, uint8_t RegisterValue) +{ + uint32_t result = 0; + + /*!< While the bus is busy */ + CODECTimeout = CODEC_LONG_TIMEOUT; + while(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Start the config sequence */ + I2C_GenerateSTART(CODEC_I2C, ENABLE); + + /* Test on EV5 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Transmit the slave address and enable writing operation */ + I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Transmitter); + + /* Test on EV6 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Transmit the first address for write operation */ + I2C_SendData(CODEC_I2C, RegisterAddr); + + /* Test on EV8 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Prepare the register value to be sent */ + I2C_SendData(CODEC_I2C, RegisterValue); + + /*!< Wait till all data have been physically transferred on the bus */ + CODECTimeout = CODEC_LONG_TIMEOUT; + while(!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF)) + { + if((CODECTimeout--) == 0) Codec_TIMEOUT_UserCallback(); + } + + /* End the configuration sequence */ + I2C_GenerateSTOP(CODEC_I2C, ENABLE); + +#ifdef VERIFY_WRITTENDATA + /* Verify that the data has been correctly written */ + result = (Codec_ReadRegister(RegisterAddr) == RegisterValue)? 0:1; +#endif /* VERIFY_WRITTENDATA */ + + /* Return the verifying value: 0 (Passed) or 1 (Failed) */ + return result; +} + +/** + * @brief Reads and returns the value of an audio codec register through the + * control interface (I2C). + * @param RegisterAddr: Address of the register to be read. + * @retval Value of the register to be read or dummy value if the communication + * fails. + */ +static uint32_t Codec_ReadRegister(uint8_t RegisterAddr) +{ + uint32_t result = 0; + + /*!< While the bus is busy */ + CODECTimeout = CODEC_LONG_TIMEOUT; + while(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Start the config sequence */ + I2C_GenerateSTART(CODEC_I2C, ENABLE); + + /* Test on EV5 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Transmit the slave address and enable writing operation */ + I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Transmitter); + + /* Test on EV6 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /* Transmit the register address to be read */ + I2C_SendData(CODEC_I2C, RegisterAddr); + + /* Test on EV8 and clear it */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while (I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF) == RESET) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /*!< Send START condition a second time */ + I2C_GenerateSTART(CODEC_I2C, ENABLE); + + /*!< Test on EV5 and clear it (cleared by reading SR1 then writing to DR) */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT)) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /*!< Send Codec address for read */ + I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Receiver); + + /* Wait on ADDR flag to be set (ADDR is still not cleared at this level */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_ADDR) == RESET) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /*!< Disable Acknowledgment */ + I2C_AcknowledgeConfig(CODEC_I2C, DISABLE); + + /* Clear ADDR register by reading SR1 then SR2 register (SR1 has already been read) */ + (void)CODEC_I2C->SR2; + + /*!< Send STOP Condition */ + I2C_GenerateSTOP(CODEC_I2C, ENABLE); + + /* Wait for the byte to be received */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_RXNE) == RESET) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /*!< Read the byte received from the Codec */ + result = I2C_ReceiveData(CODEC_I2C); + + /* Wait to make sure that STOP flag has been cleared */ + CODECTimeout = CODEC_FLAG_TIMEOUT; + while(CODEC_I2C->CR1 & I2C_CR1_STOP) + { + if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback(); + } + + /*!< Re-Enable Acknowledgment to be ready for another reception */ + I2C_AcknowledgeConfig(CODEC_I2C, ENABLE); + + /* Clear AF flag for next communication */ + I2C_ClearFlag(CODEC_I2C, I2C_FLAG_AF); + + /* Return the byte read from Codec */ + return result; +} + +/** + * @brief Initializes the Audio Codec control interface (I2C). + * @param None + * @retval None + */ +static void Codec_CtrlInterface_Init(void) +{ + I2C_InitTypeDef I2C_InitStructure; + + /* Enable the CODEC_I2C peripheral clock */ + RCC_APB1PeriphClockCmd(CODEC_I2C_CLK, ENABLE); + + /* CODEC_I2C peripheral configuration */ + I2C_DeInit(CODEC_I2C); + I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; + I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; + I2C_InitStructure.I2C_OwnAddress1 = 0x33; + I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; + I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; + I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED; + /* Enable the I2C peripheral */ + I2C_Cmd(CODEC_I2C, ENABLE); + I2C_Init(CODEC_I2C, &I2C_InitStructure); +} + +/** + * @brief Restore the Audio Codec control interface to its default state. + * This function doesn't de-initialize the I2C because the I2C peripheral + * may be used by other modules. + * @param None + * @retval None + */ +static void Codec_CtrlInterface_DeInit(void) +{ + /* Disable the I2C peripheral */ /* This step is not done here because + the I2C interface can be used by other modules */ + /* I2C_DeInit(CODEC_I2C); */ +} + +/** + * @brief Initializes the Audio Codec audio interface (I2S) + * @note This function assumes that the I2S input clock (through PLL_R in + * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) + * is already configured and ready to be used. + * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. + * @retval None + */ +static void Codec_AudioInterface_Init(uint32_t AudioFreq) +{ + I2S_InitTypeDef I2S_InitStructure; + DAC_InitTypeDef DAC_InitStructure; + + /* Enable the CODEC_I2S peripheral clock */ + RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, ENABLE); + + /* CODEC_I2S peripheral configuration */ + SPI_I2S_DeInit(CODEC_I2S); + I2S_InitStructure.I2S_AudioFreq = AudioFreq; + I2S_InitStructure.I2S_Standard = I2S_STANDARD; + I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b; + I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low; +#ifdef DAC_USE_I2S_DMA + if (CurrAudioInterface == AUDIO_INTERFACE_DAC) + { + I2S_InitStructure.I2S_Mode = I2S_Mode_MasterRx; + } + else + { +#else + I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx; +#endif +#ifdef DAC_USE_I2S_DMA + } +#endif /* DAC_USE_I2S_DMA */ +#ifdef CODEC_MCLK_ENABLED + I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable; +#elif defined(CODEC_MCLK_DISABLED) + I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable; +#else +#error "No selection for the MCLK output has been defined !" +#endif /* CODEC_MCLK_ENABLED */ + + /* Initialize the I2S peripheral with the structure above */ + I2S_Init(CODEC_I2S, &I2S_InitStructure); + + + /* Configure the DAC interface */ + if (CurrAudioInterface == AUDIO_INTERFACE_DAC) + { + /* DAC Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + /* DAC channel1 Configuration */ + DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(AUDIO_DAC_CHANNEL, &DAC_InitStructure); + + /* Enable DAC Channel1 */ + DAC_Cmd(AUDIO_DAC_CHANNEL, ENABLE); + } + + /* The I2S peripheral will be enabled only in the EVAL_AUDIO_Play() function + or by user functions if DMA mode not enabled */ +} + +/** + * @brief Restores the Audio Codec audio interface to its default state. + * @param None + * @retval None + */ +static void Codec_AudioInterface_DeInit(void) +{ + /* Disable the CODEC_I2S peripheral (in case it hasn't already been disabled) */ + I2S_Cmd(CODEC_I2S, DISABLE); + + /* Deinitialize the CODEC_I2S peripheral */ + SPI_I2S_DeInit(CODEC_I2S); + + /* Disable the CODEC_I2S peripheral clock */ + RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, DISABLE); +} + +/** + * @brief Initializes IOs used by the Audio Codec (on the control and audio + * interfaces). + * @param None + * @retval None + */ +static void Codec_GPIO_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable Reset GPIO Clock */ + RCC_AHB1PeriphClockCmd(AUDIO_RESET_GPIO_CLK,ENABLE); + + /* Audio reset pin configuration -------------------------------------------------*/ + GPIO_InitStructure.GPIO_Pin = AUDIO_RESET_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(AUDIO_RESET_GPIO, &GPIO_InitStructure); + + /* Enable I2S and I2C GPIO clocks */ + RCC_AHB1PeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE); + + /* CODEC_I2C SCL and SDA pins configuration -------------------------------------*/ + GPIO_InitStructure.GPIO_Pin = CODEC_I2C_SCL_PIN | CODEC_I2C_SDA_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(CODEC_I2C_GPIO, &GPIO_InitStructure); + /* Connect pins to I2C peripheral */ + GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2S_SCL_PINSRC, CODEC_I2C_GPIO_AF); + GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2S_SDA_PINSRC, CODEC_I2C_GPIO_AF); + + /* CODEC_I2S pins configuration: WS, SCK and SD pins -----------------------------*/ + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_SD_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure); + + /* Connect pins to I2S peripheral */ + GPIO_PinAFConfig(CODEC_I2S_WS_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF); + GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF); + + if (CurrAudioInterface != AUDIO_INTERFACE_DAC) + { + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN ; + GPIO_Init(CODEC_I2S_WS_GPIO, &GPIO_InitStructure); + GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SD_PINSRC, CODEC_I2S_GPIO_AF); + } + else + { + /* GPIOA clock enable (to be used with DAC) */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + + /* DAC channel 1 & 2 (DAC_OUT1 = PA.4) configuration */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + } + +#ifdef CODEC_MCLK_ENABLED + /* CODEC_I2S pins configuration: MCK pin */ + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_MCK_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(CODEC_I2S_MCK_GPIO, &GPIO_InitStructure); + /* Connect pins to I2S peripheral */ + GPIO_PinAFConfig(CODEC_I2S_MCK_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_GPIO_AF); +#endif /* CODEC_MCLK_ENABLED */ +} + +/** + * @brief Restores the IOs used by the Audio Codec interface to their default state. + * @param None + * @retval None + */ +static void Codec_GPIO_DeInit(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + + /* Deinitialize all the GPIOs used by the driver */ + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_SD_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN ; + GPIO_Init(CODEC_I2S_WS_GPIO, &GPIO_InitStructure); + + /* Disconnect pins from I2S peripheral */ + GPIO_PinAFConfig(CODEC_I2S_WS_GPIO, CODEC_I2S_WS_PINSRC, 0x00); + GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, 0x00); + GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SD_PINSRC, 0x00); + +#ifdef CODEC_MCLK_ENABLED + /* CODEC_I2S pins deinitialization: MCK pin */ + GPIO_InitStructure.GPIO_Pin = CODEC_I2S_MCK_PIN; + GPIO_Init(CODEC_I2S_MCK_GPIO, &GPIO_InitStructure); + /* Disconnect pins from I2S peripheral */ + GPIO_PinAFConfig(CODEC_I2S_MCK_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_GPIO_AF); +#endif /* CODEC_MCLK_ENABLED */ +} + +/** + * @brief Inserts a delay time (not accurate timing). + * @param nCount: specifies the delay time length. + * @retval None + */ +static void Delay( __IO uint32_t nCount) +{ + for (; nCount != 0; nCount--); +} + +#ifdef USE_DEFAULT_TIMEOUT_CALLBACK +/** + * @brief Basic management of the timeout situation. + * @param None + * @retval None + */ +uint32_t Codec_TIMEOUT_UserCallback(void) +{ + /* Block communication and all processes */ + while (1) + { + } +} +#endif /* USE_DEFAULT_TIMEOUT_CALLBACK */ +/*======================== + + Audio MAL Interface Control Functions + + ==============================*/ + +/** + * @brief Initializes and prepares the Media to perform audio data transfer + * from Media to the I2S peripheral. + * @param None + * @retval None + */ +static void Audio_MAL_Init(void) +{ + +#ifdef I2S_INTERRUPT + NVIC_InitTypeDef NVIC_InitStructure; + + NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, ENABLE); + + I2S_Cmd(SPI3, ENABLE); +#else +#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN) + NVIC_InitTypeDef NVIC_InitStructure; +#endif + + if (CurrAudioInterface == AUDIO_INTERFACE_I2S) + { + /* Enable the DMA clock */ + RCC_AHB1PeriphClockCmd(AUDIO_MAL_DMA_CLOCK, ENABLE); + + /* Configure the DMA Stream */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + DMA_DeInit(AUDIO_MAL_DMA_STREAM); + /* Set the parameters to be configured */ + DMA_InitStructure.DMA_Channel = AUDIO_MAL_DMA_CHANNEL; + DMA_InitStructure.DMA_PeripheralBaseAddr = AUDIO_MAL_DMA_DREG; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; /* This field will be configured in play function */ + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = (uint32_t)0xFFFE; /* This field will be configured in play function */ + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = AUDIO_MAL_DMA_PERIPH_DATA_SIZE; + DMA_InitStructure.DMA_MemoryDataSize = AUDIO_MAL_DMA_MEM_DATA_SIZE; +#ifdef AUDIO_MAL_MODE_NORMAL + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; +#elif defined(AUDIO_MAL_MODE_CIRCULAR) + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; +#else +#error "AUDIO_MAL_MODE_NORMAL or AUDIO_MAL_MODE_CIRCULAR should be selected !!" +#endif /* AUDIO_MAL_MODE_NORMAL */ + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_InitStructure); + + /* Enable the selected DMA interrupts (selected in "stm32f4_discovery_eval_audio_codec.h" defines) */ +#ifdef AUDIO_MAL_DMA_IT_TC_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TC, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_TC_EN */ +#ifdef AUDIO_MAL_DMA_IT_HT_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_HT, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_HT_EN */ +#ifdef AUDIO_MAL_DMA_IT_TE_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TE | DMA_IT_FE | DMA_IT_DME, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_TE_EN */ + +#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN) + /* I2S DMA IRQ Channel configuration */ + NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#endif + } + +#ifdef DAC_USE_I2S_DMA + else + { + /* Enable the DMA clock */ + RCC_AHB1PeriphClockCmd(AUDIO_MAL_DMA_CLOCK, ENABLE); + + /* Configure the DMA Stream */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + DMA_DeInit(AUDIO_MAL_DMA_STREAM); + /* Set the parameters to be configured */ + DMA_InitStructure.DMA_Channel = AUDIO_MAL_DMA_CHANNEL; + DMA_InitStructure.DMA_PeripheralBaseAddr = AUDIO_MAL_DMA_DREG; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; /* This field will be configured in play function */ + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = (uint32_t)0xFFFE; /* This field will be configured in play function */ + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = AUDIO_MAL_DMA_PERIPH_DATA_SIZE; + DMA_InitStructure.DMA_MemoryDataSize = AUDIO_MAL_DMA_MEM_DATA_SIZE; +#ifdef AUDIO_MAL_MODE_NORMAL + DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; +#elif defined(AUDIO_MAL_MODE_CIRCULAR) + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; +#else +#error "AUDIO_MAL_MODE_NORMAL or AUDIO_MAL_MODE_CIRCULAR should be selected !!" +#endif /* AUDIO_MAL_MODE_NORMAL */ + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_InitStructure); + + /* Enable the selected DMA interrupts (selected in "stm32f4_discovery_eval_audio_codec.h" defines) */ +#ifdef AUDIO_MAL_DMA_IT_TC_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TC, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_TC_EN */ +#ifdef AUDIO_MAL_DMA_IT_HT_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_HT, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_HT_EN */ +#ifdef AUDIO_MAL_DMA_IT_TE_EN + DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TE | DMA_IT_FE | DMA_IT_DME, ENABLE); +#endif /* AUDIO_MAL_DMA_IT_TE_EN */ + +#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN) + /* I2S DMA IRQ Channel configuration */ + NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#endif + } +#endif /* DAC_USE_I2S_DMA */ + + if (CurrAudioInterface == AUDIO_INTERFACE_I2S) + { + /* Enable the I2S DMA request */ + SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE); + } + else + { + /* Configure the STM32 DAC to geenrate audio analog signal */ + DAC_Config(); + +#ifndef DAC_USE_I2S_DMA + /* Enable the I2S interrupt used to write into the DAC register */ + SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, ENABLE); + + /* I2S DMA IRQ Channel configuration */ + NVIC_InitStructure.NVIC_IRQChannel = CODEC_I2S_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +#else + /* Enable the I2S DMA request */ + SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Rx, ENABLE); +#endif /* DAC_USE_I2S_DMA */ + } +#endif +} + +/** + * @brief Restore default state of the used Media. + * @param None + * @retval None + */ +static void Audio_MAL_DeInit(void) +{ +#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN) + NVIC_InitTypeDef NVIC_InitStructure; + + /* Deinitialize the NVIC interrupt for the I2S DMA Stream */ + NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO; + NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; + NVIC_Init(&NVIC_InitStructure); +#endif + + /* Disable the DMA stream before the deinit */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + + /* Dinitialize the DMA Stream */ + DMA_DeInit(AUDIO_MAL_DMA_STREAM); + + /* + The DMA clock is not disabled, since it can be used by other streams + */ +} + +/** + * @brief Starts playing audio stream from the audio Media. + * @param None + * @retval None + */ +static void Audio_MAL_Play(uint32_t Addr, uint32_t Size) +{ + if (CurrAudioInterface == AUDIO_INTERFACE_I2S) + { + /* Configure the buffer address and size */ + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Addr; + DMA_InitStructure.DMA_BufferSize = (uint32_t)Size; + + /* Configure the DMA Stream with the new parameters */ + DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_InitStructure); + + /* Enable the I2S DMA Stream*/ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, ENABLE); + } +#ifndef DAC_USE_I2S_DMA + else + { + /* Configure the buffer address and size */ + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Addr; + DMA_InitStructure.DMA_BufferSize = (uint32_t)Size; + + /* Configure the DMA Stream with the new parameters */ + DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_InitStructure); + + /* Enable the I2S DMA Stream*/ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, ENABLE); + } +#endif /* DAC_USE_I2S_DMA */ + + /* If the I2S peripheral is still not enabled, enable it */ + if ((CODEC_I2S->I2SCFGR & I2S_ENABLE_MASK) == 0) + { + I2S_Cmd(CODEC_I2S, ENABLE); + } +} + +/** + * @brief Pauses or Resumes the audio stream playing from the Media. + * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different + * from 0) to resume. + * @param Addr: Address from/at which the audio stream should resume/pause. + * @retval None + */ +static void Audio_MAL_PauseResume(uint32_t Cmd, uint32_t Addr) +{ + /* Pause the audio file playing */ + if (Cmd == AUDIO_PAUSE) + { + /* Disable the I2S DMA request */ + SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, DISABLE); + + /* Pause the I2S DMA Stream + Note. For the STM32F4xx devices, the DMA implements a pause feature, + by disabling the stream, all configuration is preserved and data + transfer is paused till the next enable of the stream. + This feature is not available on STM32F4xx devices. */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + } + else /* AUDIO_RESUME */ + { + /* Enable the I2S DMA request */ + SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE); + + /* Resume the I2S DMA Stream + Note. For the STM32F4xx devices, the DMA implements a pause feature, + by disabling the stream, all configuration is preserved and data + transfer is paused till the next enable of the stream. + This feature is not available on STM32F4xx devices. */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, ENABLE); + + /* If the I2S peripheral is still not enabled, enable it */ + if ((CODEC_I2S->I2SCFGR & I2S_ENABLE_MASK) == 0) + { + I2S_Cmd(CODEC_I2S, ENABLE); + } + } +} + +/** + * @brief Stops audio stream playing on the used Media. + * @param None + * @retval None + */ +static void Audio_MAL_Stop(void) +{ + /* Stop the Transfer on the I2S side: Stop and disable the DMA stream */ + DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE); + + /* Clear all the DMA flags for the next transfer */ + DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC |AUDIO_MAL_DMA_FLAG_HT | \ + AUDIO_MAL_DMA_FLAG_FE | AUDIO_MAL_DMA_FLAG_TE); + + /* + The I2S DMA requests are not disabled here. + */ + + /* In all modes, disable the I2S peripheral */ + I2S_Cmd(CODEC_I2S, DISABLE); +} + +/** + * @brief DAC Channel1 Configuration + * @param None + * @retval None + */ +void DAC_Config(void) +{ + DAC_InitTypeDef DAC_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + + /* DMA1 clock and GPIOA clock enable (to be used with DAC) */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE); + + /* DAC Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + /* DAC channel 1 & 2 (DAC_OUT1 = PA.4) configuration */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* DAC channel1 Configuration */ + DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(AUDIO_DAC_CHANNEL, &DAC_InitStructure); + + /* Enable DAC Channel1 */ + DAC_Cmd(AUDIO_DAC_CHANNEL, ENABLE); +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.h b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.h new file mode 100644 index 0000000..33ba0e7 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_audio_codec.h @@ -0,0 +1,304 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery_audio_codec.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file contains all the functions prototypes for the + * stm32f4_discovery_audio_codec.c driver. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4_DISCOVERY_AUDIOCODEC_H +#define __STM32F4_DISCOVERY_AUDIOCODEC_H + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx.h" +#include "stm32f4xx_gpio.h" + +/** @addtogroup Utilities + * @{ + */ + + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC + * @{ + */ + + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Exported_Types + * @{ + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Exported_Constants + * @{ + */ + +/*------------------------------------ + CONFIGURATION: Audio Codec Driver Configuration parameters + ----------------------------------------*/ +#define I2S_INTERRUPT +/* Audio Transfer mode (DMA, Interrupt or Polling) */ +#define AUDIO_MAL_MODE_NORMAL /* Uncomment this line to enable the audio + Transfer using DMA */ +/* #define AUDIO_MAL_MODE_CIRCULAR */ /* Uncomment this line to enable the audio + Transfer using DMA */ + +/* For the DMA modes select the interrupt that will be used */ +#define AUDIO_MAL_DMA_IT_TC_EN /* Uncomment this line to enable DMA Transfer Complete interrupt */ +/* #define AUDIO_MAL_DMA_IT_HT_EN */ /* Uncomment this line to enable DMA Half Transfer Complete interrupt */ +/* #define AUDIO_MAL_DMA_IT_TE_EN */ /* Uncomment this line to enable DMA Transfer Error interrupt */ + +/* Select the interrupt preemption priority and subpriority for the DMA interrupt */ +#define EVAL_AUDIO_IRQ_PREPRIO 0 /* Select the preemption priority level(0 is the highest) */ +#define EVAL_AUDIO_IRQ_SUBRIO 0 /* Select the sub-priority level (0 is the highest) */ + +/* Uncomment the following line to use the default Codec_TIMEOUT_UserCallback() + function implemented in stm32f4_discovery_audio_codec.c file. + Codec_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +/* #define USE_DEFAULT_TIMEOUT_CALLBACK */ + +/* Enable this define to use the I2S DMA for writing into DAC register */ +//#define DAC_USE_I2S_DMA +/*----------------------------------------------------------------------------*/ + +/*------------------------------------ + OPTIONAL Configuration defines parameters + ----------------------------------------*/ +/* I2C clock speed configuration (in Hz) + WARNING: + Make sure that this define is not already declared in other files (ie. + stm322xg_eval.h file). It can be used in parallel by other modules. */ +#ifndef I2C_SPEED + #define I2C_SPEED 100000 +#endif /* I2C_SPEED */ + +/* Uncomment defines below to select standard for audio communication between + Codec and I2S peripheral */ +#define I2S_STANDARD_PHILLIPS +/* #define I2S_STANDARD_MSB */ +/* #define I2S_STANDARD_LSB */ + +/* Uncomment the defines below to select if the Master clock mode should be + enabled or not */ +#define CODEC_MCLK_ENABLED +/* #deine CODEC_MCLK_DISABLED */ + +/* Uncomment this line to enable verifying data sent to codec after each write + operation */ +#define VERIFY_WRITTENDATA +/*----------------------------------------------------------------------------*/ + +/*----------------------------------- + Hardware Configuration defines parameters + -----------------------------------------*/ +/* Audio Reset Pin definition */ +#define AUDIO_RESET_GPIO_CLK RCC_AHB1Periph_GPIOD +#define AUDIO_RESET_PIN GPIO_Pin_4 +#define AUDIO_RESET_GPIO GPIOD + +/* I2S peripheral configuration defines */ +#define CODEC_I2S SPI3 +#define CODEC_I2S_CLK RCC_APB1Periph_SPI3 +#define CODEC_I2S_ADDRESS 0x40003C0C +#define CODEC_I2S_GPIO_AF GPIO_AF_SPI3 +#define CODEC_I2S_IRQ SPI3_IRQn +#define CODEC_I2S_GPIO_CLOCK (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA) +#define CODEC_I2S_WS_PIN GPIO_Pin_4 +#define CODEC_I2S_SCK_PIN GPIO_Pin_10 +#define CODEC_I2S_SD_PIN GPIO_Pin_12 +#define CODEC_I2S_MCK_PIN GPIO_Pin_7 +#define CODEC_I2S_WS_PINSRC GPIO_PinSource4 +#define CODEC_I2S_SCK_PINSRC GPIO_PinSource10 +#define CODEC_I2S_SD_PINSRC GPIO_PinSource12 +#define CODEC_I2S_MCK_PINSRC GPIO_PinSource7 +#define CODEC_I2S_GPIO GPIOC +#define CODEC_I2S_WS_GPIO GPIOA +#define CODEC_I2S_MCK_GPIO GPIOC +#define Audio_I2S_IRQHandler SPI3_IRQHandler + + + #define AUDIO_MAL_DMA_PERIPH_DATA_SIZE DMA_PeripheralDataSize_HalfWord + #define AUDIO_MAL_DMA_MEM_DATA_SIZE DMA_MemoryDataSize_HalfWord + #define DMA_MAX_SZE 0xFFFF + + + #define DAC_DHR12L1_ADDRESS 0x4000740C + #define DAC_DHR12R1_ADDRESS 0x40007408 + #define DAC_DHR8R1_ADDRESS 0x40007410 + #define AUDIO_DAC_CHANNEL DAC_Channel_1 + + /* I2S DMA Stream definitions */ + #define AUDIO_I2S_DMA_CLOCK RCC_AHB1Periph_DMA1 + #define AUDIO_I2S_DMA_STREAM DMA1_Stream7 + #define AUDIO_I2S_DMA_DREG CODEC_I2S_ADDRESS + #define AUDIO_I2S_DMA_CHANNEL DMA_Channel_0 + #define AUDIO_I2S_DMA_IRQ DMA1_Stream7_IRQn + #define AUDIO_I2S_DMA_FLAG_TC DMA_FLAG_TCIF7 + #define AUDIO_I2S_DMA_FLAG_HT DMA_FLAG_HTIF7 + #define AUDIO_I2S_DMA_FLAG_FE DMA_FLAG_FEIF7 + #define AUDIO_I2S_DMA_FLAG_TE DMA_FLAG_TEIF7 + #define AUDIO_I2S_DMA_FLAG_DME DMA_FLAG_DMEIF7 + + #define Audio_MAL_I2S_IRQHandler DMA1_Stream7_IRQHandler + + + /* DAC DMA Stream definitions */ + #define AUDIO_DAC_DMA_CLOCK RCC_AHB1Periph_DMA1 + #define AUDIO_DAC_DMA_STREAM DMA1_Stream0 + #define AUDIO_DAC_DMA_DREG DAC_DHR12L1_ADDRESS + #define AUDIO_DAC_DMA_CHANNEL DMA_Channel_0 + #define AUDIO_DAC_DMA_IRQ DMA1_Stream0_IRQn + #define AUDIO_DAC_DMA_FLAG_TC DMA_FLAG_TCIF0 + #define AUDIO_DAC_DMA_FLAG_HT DMA_FLAG_HTIF0 + #define AUDIO_DAC_DMA_FLAG_FE DMA_FLAG_FEIF0 + #define AUDIO_DAC_DMA_FLAG_TE DMA_FLAG_TEIF0 + #define AUDIO_DAC_DMA_FLAG_DME DMA_FLAG_DMEIF0 + + #define Audio_MAL_DAC_IRQHandler DMA1_Stream0_IRQHandler + + +/* I2C peripheral configuration defines (control interface of the audio codec) */ +#define CODEC_I2C I2C1 +#define CODEC_I2C_CLK RCC_APB1Periph_I2C1 +#define CODEC_I2C_GPIO_CLOCK RCC_AHB1Periph_GPIOB +#define CODEC_I2C_GPIO_AF GPIO_AF_I2C1 +#define CODEC_I2C_GPIO GPIOB +#define CODEC_I2C_SCL_PIN GPIO_Pin_6 +#define CODEC_I2C_SDA_PIN GPIO_Pin_9 +#define CODEC_I2S_SCL_PINSRC GPIO_PinSource6 +#define CODEC_I2S_SDA_PINSRC GPIO_PinSource9 + +/* Maximum Timeout values for flags and events waiting loops. These timeouts are + not based on accurate values, they just guarantee that the application will + not remain stuck if the I2C communication is corrupted. + You may modify these timeout values depending on CPU frequency and application + conditions (interrupts routines ...). */ +#define CODEC_FLAG_TIMEOUT ((uint32_t)0x1000) +#define CODEC_LONG_TIMEOUT ((uint32_t)(300 * CODEC_FLAG_TIMEOUT)) +/*----------------------------------------------------------------------------*/ + +/*----------------------------------- + Audio Codec User defines + -----------------------------------------*/ +/* Audio interface : I2S or DAC */ +#define AUDIO_INTERFACE_I2S 1 +#define AUDIO_INTERFACE_DAC 2 + +/* Codec output DEVICE */ +#define OUTPUT_DEVICE_SPEAKER 1 +#define OUTPUT_DEVICE_HEADPHONE 2 +#define OUTPUT_DEVICE_BOTH 3 +#define OUTPUT_DEVICE_AUTO 4 + +/* Volume Levels values */ +#define DEFAULT_VOLMIN 0x00 +#define DEFAULT_VOLMAX 0xFF +#define DEFAULT_VOLSTEP 0x04 + +#define AUDIO_PAUSE 0 +#define AUDIO_RESUME 1 + +/* Codec POWER DOWN modes */ +#define CODEC_PDWN_HW 1 +#define CODEC_PDWN_SW 2 + +/* MUTE commands */ +#define AUDIO_MUTE_ON 1 +#define AUDIO_MUTE_OFF 0 +/*----------------------------------------------------------------------------*/ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Exported_Macros + * @{ + */ +#define VOLUME_CONVERT(x) ((Volume > 100)? 100:((uint8_t)((Volume * 255) / 100))) +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_AUDIO_CODEC_Exported_Functions + * @{ + */ +void EVAL_AUDIO_SetAudioInterface(uint32_t Interface); +uint32_t EVAL_AUDIO_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +uint32_t EVAL_AUDIO_DeInit(void); +uint32_t EVAL_AUDIO_Play(uint16_t* pBuffer, uint32_t Size); +uint32_t EVAL_AUDIO_PauseResume(uint32_t Cmd); +uint32_t EVAL_AUDIO_Stop(uint32_t CodecPowerDown_Mode); +uint32_t EVAL_AUDIO_VolumeCtl(uint8_t Volume); +uint32_t EVAL_AUDIO_Mute(uint32_t Command); +void DAC_Config(void); + +/* User Callbacks: user has to implement these functions in his code if + they are needed. -----------------------------------------------------------*/ + +uint16_t EVAL_AUDIO_GetSampleCallBack(void); + +/* This function is called when the requested data has been completely transferred. + In Normal mode (when the define AUDIO_MAL_MODE_NORMAL is enabled) this function + is called at the end of the whole audio file. + In circular mode (when the define AUDIO_MAL_MODE_CIRCULAR is enabled) this + function is called at the end of the current buffer transmission. */ +void EVAL_AUDIO_TransferComplete_CallBack(uint32_t pBuffer, uint32_t Size); + +/* This function is called when half of the requested buffer has been transferred + This callback is useful in Circular mode only (when AUDIO_MAL_MODE_CIRCULAR + define is enabled)*/ +void EVAL_AUDIO_HalfTransfer_CallBack(uint32_t pBuffer, uint32_t Size); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void EVAL_AUDIO_Error_CallBack(void* pData); + +/* Codec_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...) on the Codec control interface (I2C). + You can use the default timeout callback implementation by uncommenting the + define USE_DEFAULT_TIMEOUT_CALLBACK in stm32f4_discovery_audio_codec.h file. + Typically the user implementation of this callback should reset I2C peripheral + and re-initialize communication or in worst case reset all the application. */ +uint32_t Codec_TIMEOUT_UserCallback(void); + +#endif /* __STM32F4_DISCOVERY_AUDIOCODEC_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c new file mode 100644 index 0000000..d354dc4 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.c @@ -0,0 +1,504 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery_lis302dl.c + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file provides a set of functions needed to manage the LIS302DL + * MEMS accelerometer available on STM32F4-Discovery Kit. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4_discovery_lis302dl.h" +//ADDED BY ME!!!!!!!!!!!!!!!!!!!! +#include "stm32f4xx_conf.h" + +/** @addtogroup Utilities + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY_LIS302DL + * @{ + */ + + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Defines + * @{ + */ +__IO uint32_t LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT; + +/* Read/Write command */ +#define READWRITE_CMD ((uint8_t)0x80) +/* Multiple byte read/write command */ +#define MULTIPLEBYTE_CMD ((uint8_t)0x40) +/* Dummy Byte Send by the SPI Master device in order to generate the Clock to the Slave device */ +#define DUMMY_BYTE ((uint8_t)0x00) + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Variables + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_FunctionPrototypes + * @{ + */ +static uint8_t LIS302DL_SendByte(uint8_t byte); +static void LIS302DL_LowLevel_Init(void); +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Private_Functions + * @{ + */ + + +/** + * @brief Set LIS302DL Initialization. + * @param LIS302DL_Config_Struct: pointer to a LIS302DL_Config_TypeDef structure + * that contains the configuration setting for the LIS302DL. + * @retval None + */ +void LIS302DL_Init(LIS302DL_InitTypeDef *LIS302DL_InitStruct) +{ + uint8_t ctrl = 0x00; + + /* Configure the low level interface ---------------------------------------*/ + LIS302DL_LowLevel_Init(); + + /* Configure MEMS: data rate, power mode, full scale, self test and axes */ + ctrl = (uint8_t) (LIS302DL_InitStruct->Output_DataRate | LIS302DL_InitStruct->Power_Mode | \ + LIS302DL_InitStruct->Full_Scale | LIS302DL_InitStruct->Self_Test | \ + LIS302DL_InitStruct->Axes_Enable); + + /* Write value to MEMS CTRL_REG1 regsister */ + LIS302DL_Write(&ctrl, LIS302DL_CTRL_REG1_ADDR, 1); +} + +/** + * @brief Set LIS302DL Internal High Pass Filter configuration. + * @param LIS302DL_Filter_ConfigTypeDef: pointer to a LIS302DL_FilterConfig_TypeDef + * structure that contains the configuration setting for the LIS302DL Filter. + * @retval None + */ +void LIS302DL_FilterConfig(LIS302DL_FilterConfigTypeDef *LIS302DL_FilterConfigStruct) +{ + uint8_t ctrl = 0x00; + + /* Read CTRL_REG2 register */ + LIS302DL_Read(&ctrl, LIS302DL_CTRL_REG2_ADDR, 1); + + /* Clear high pass filter cut-off level, interrupt and data selection bits*/ + ctrl &= (uint8_t)~(LIS302DL_FILTEREDDATASELECTION_OUTPUTREGISTER | \ + LIS302DL_HIGHPASSFILTER_LEVEL_3 | \ + LIS302DL_HIGHPASSFILTERINTERRUPT_1_2); + /* Configure MEMS high pass filter cut-off level, interrupt and data selection bits */ + ctrl |= (uint8_t)(LIS302DL_FilterConfigStruct->HighPassFilter_Data_Selection | \ + LIS302DL_FilterConfigStruct->HighPassFilter_CutOff_Frequency | \ + LIS302DL_FilterConfigStruct->HighPassFilter_Interrupt); + + /* Write value to MEMS CTRL_REG2 register */ + LIS302DL_Write(&ctrl, LIS302DL_CTRL_REG2_ADDR, 1); +} + +/** + * @brief Set LIS302DL Interrupt configuration + * @param LIS302DL_InterruptConfig_TypeDef: pointer to a LIS302DL_InterruptConfig_TypeDef + * structure that contains the configuration setting for the LIS302DL Interrupt. + * @retval None + */ +void LIS302DL_InterruptConfig(LIS302DL_InterruptConfigTypeDef *LIS302DL_IntConfigStruct) +{ + uint8_t ctrl = 0x00; + + /* Read CLICK_CFG register */ + LIS302DL_Read(&ctrl, LIS302DL_CLICK_CFG_REG_ADDR, 1); + + /* Configure latch Interrupt request, click interrupts and double click interrupts */ + ctrl = (uint8_t)(LIS302DL_IntConfigStruct->Latch_Request| \ + LIS302DL_IntConfigStruct->SingleClick_Axes | \ + LIS302DL_IntConfigStruct->DoubleClick_Axes); + + /* Write value to MEMS CLICK_CFG register */ + LIS302DL_Write(&ctrl, LIS302DL_CLICK_CFG_REG_ADDR, 1); +} + +/** + * @brief Change the lowpower mode for LIS302DL + * @param LowPowerMode: new state for the lowpower mode. + * This parameter can be one of the following values: + * @arg LIS302DL_LOWPOWERMODE_POWERDOWN: Power down mode + * @arg LIS302DL_LOWPOWERMODE_ACTIVE: Active mode + * @retval None + */ +void LIS302DL_LowpowerCmd(uint8_t LowPowerMode) +{ + uint8_t tmpreg; + + /* Read CTRL_REG1 register */ + LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); + + /* Set new low power mode configuration */ + tmpreg &= (uint8_t)~LIS302DL_LOWPOWERMODE_ACTIVE; + tmpreg |= LowPowerMode; + + /* Write value to MEMS CTRL_REG1 regsister */ + LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); +} + +/** + * @brief Data Rate command + * @param DataRateValue: Data rate value + * This parameter can be one of the following values: + * @arg LIS302DL_DATARATE_100: 100 Hz output data rate + * @arg LIS302DL_DATARATE_400: 400 Hz output data rate + * @retval None + */ +void LIS302DL_DataRateCmd(uint8_t DataRateValue) +{ + uint8_t tmpreg; + + /* Read CTRL_REG1 register */ + LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); + + /* Set new Data rate configuration */ + tmpreg &= (uint8_t)~LIS302DL_DATARATE_400; + tmpreg |= DataRateValue; + + /* Write value to MEMS CTRL_REG1 regsister */ + LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); +} + +/** + * @brief Change the Full Scale of LIS302DL + * @param FS_value: new full scale value. + * This parameter can be one of the following values: + * @arg LIS302DL_FULLSCALE_2_3: +-2.3g + * @arg LIS302DL_FULLSCALE_9_2: +-9.2g + * @retval None + */ +void LIS302DL_FullScaleCmd(uint8_t FS_value) +{ + uint8_t tmpreg; + + /* Read CTRL_REG1 register */ + LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); + + /* Set new full scale configuration */ + tmpreg &= (uint8_t)~LIS302DL_FULLSCALE_9_2; + tmpreg |= FS_value; + + /* Write value to MEMS CTRL_REG1 regsister */ + LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG1_ADDR, 1); +} + +/** + * @brief Reboot memory content of LIS302DL + * @param None + * @retval None + */ +void LIS302DL_RebootCmd(void) +{ + uint8_t tmpreg; + /* Read CTRL_REG2 register */ + LIS302DL_Read(&tmpreg, LIS302DL_CTRL_REG2_ADDR, 1); + + /* Enable or Disable the reboot memory */ + tmpreg |= LIS302DL_BOOT_REBOOTMEMORY; + + /* Write value to MEMS CTRL_REG2 regsister */ + LIS302DL_Write(&tmpreg, LIS302DL_CTRL_REG2_ADDR, 1); +} + +/** + * @brief Writes one byte to the LIS302DL. + * @param pBuffer : pointer to the buffer containing the data to be written to the LIS302DL. + * @param WriteAddr : LIS302DL's internal address to write to. + * @param NumByteToWrite: Number of bytes to write. + * @retval None + */ +void LIS302DL_Write(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) +{ + /* Configure the MS bit: + - When 0, the address will remain unchanged in multiple read/write commands. + - When 1, the address will be auto incremented in multiple read/write commands. + */ + if(NumByteToWrite > 0x01) + { + WriteAddr |= (uint8_t)MULTIPLEBYTE_CMD; + } + /* Set chip select Low at the start of the transmission */ + LIS302DL_CS_LOW(); + + /* Send the Address of the indexed register */ + LIS302DL_SendByte(WriteAddr); + /* Send the data that will be written into the device (MSB First) */ + while(NumByteToWrite >= 0x01) + { + LIS302DL_SendByte(*pBuffer); + NumByteToWrite--; + pBuffer++; + } + + /* Set chip select High at the end of the transmission */ + LIS302DL_CS_HIGH(); +} + +/** + * @brief Reads a block of data from the LIS302DL. + * @param pBuffer : pointer to the buffer that receives the data read from the LIS302DL. + * @param ReadAddr : LIS302DL's internal address to read from. + * @param NumByteToRead : number of bytes to read from the LIS302DL. + * @retval None + */ +void LIS302DL_Read(uint8_t* pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead) +{ + if(NumByteToRead > 0x01) + { + ReadAddr |= (uint8_t)(READWRITE_CMD | MULTIPLEBYTE_CMD); + } + else + { + ReadAddr |= (uint8_t)READWRITE_CMD; + } + /* Set chip select Low at the start of the transmission */ + LIS302DL_CS_LOW(); + + /* Send the Address of the indexed register */ + LIS302DL_SendByte(ReadAddr); + + /* Receive the data that will be read from the device (MSB First) */ + while(NumByteToRead > 0x00) + { + /* Send dummy byte (0x00) to generate the SPI clock to LIS302DL (Slave device) */ + *pBuffer = LIS302DL_SendByte(DUMMY_BYTE); + NumByteToRead--; + pBuffer++; + } + + /* Set chip select High at the end of the transmission */ + LIS302DL_CS_HIGH(); +} + +/** + * @brief Read LIS302DL output register, and calculate the acceleration + * ACC[mg]=SENSITIVITY* (out_h*256+out_l)/16 (12 bit rappresentation) + * @param s16 buffer to store data + * @retval None + */ +void LIS302DL_ReadACC(int32_t* out) +{ + uint8_t buffer[6]; + uint8_t crtl, i = 0x00; + + LIS302DL_Read(&crtl, LIS302DL_CTRL_REG1_ADDR, 1); + LIS302DL_Read(buffer, LIS302DL_OUT_X_ADDR, 6); + + switch(crtl & 0x20) + { + /* FS bit = 0 ==> Sensitivity typical value = 18milligals/digit*/ + case 0x00: + for(i=0; i<0x03; i++) + { + *out =(int32_t)(LIS302DL_SENSITIVITY_2_3G * (int8_t)buffer[2*i]); + out++; + } + break; + /* FS bit = 1 ==> Sensitivity typical value = 72milligals/digit*/ + case 0x20: + for(i=0; i<0x03; i++) + { + *out =(int32_t)(LIS302DL_SENSITIVITY_9_2G * (int8_t)buffer[2*i]); + out++; + } + break; + default: + break; + } + } + +/** + * @brief Initializes the low level interface used to drive the LIS302DL + * @param None + * @retval None + */ +static void LIS302DL_LowLevel_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + SPI_InitTypeDef SPI_InitStructure; + + /* Enable the SPI periph */ + RCC_APB2PeriphClockCmd(LIS302DL_SPI_CLK, ENABLE); + + /* Enable SCK, MOSI and MISO GPIO clocks */ + RCC_AHB1PeriphClockCmd(LIS302DL_SPI_SCK_GPIO_CLK | LIS302DL_SPI_MISO_GPIO_CLK | LIS302DL_SPI_MOSI_GPIO_CLK, ENABLE); + + /* Enable CS GPIO clock */ + RCC_AHB1PeriphClockCmd(LIS302DL_SPI_CS_GPIO_CLK, ENABLE); + + /* Enable INT1 GPIO clock */ + RCC_AHB1PeriphClockCmd(LIS302DL_SPI_INT1_GPIO_CLK, ENABLE); + + /* Enable INT2 GPIO clock */ + RCC_AHB1PeriphClockCmd(LIS302DL_SPI_INT2_GPIO_CLK, ENABLE); + + GPIO_PinAFConfig(LIS302DL_SPI_SCK_GPIO_PORT, LIS302DL_SPI_SCK_SOURCE, LIS302DL_SPI_SCK_AF); + GPIO_PinAFConfig(LIS302DL_SPI_MISO_GPIO_PORT, LIS302DL_SPI_MISO_SOURCE, LIS302DL_SPI_MISO_AF); + GPIO_PinAFConfig(LIS302DL_SPI_MOSI_GPIO_PORT, LIS302DL_SPI_MOSI_SOURCE, LIS302DL_SPI_MOSI_AF); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + + /* SPI SCK pin configuration */ + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_SCK_PIN; + GPIO_Init(LIS302DL_SPI_SCK_GPIO_PORT, &GPIO_InitStructure); + + /* SPI MOSI pin configuration */ + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_MOSI_PIN; + GPIO_Init(LIS302DL_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure); + + /* SPI MISO pin configuration */ + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_MISO_PIN; + GPIO_Init(LIS302DL_SPI_MISO_GPIO_PORT, &GPIO_InitStructure); + + /* SPI configuration -------------------------------------------------------*/ + SPI_I2S_DeInit(LIS302DL_SPI); + SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; + SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; + SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; + SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; + SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; + SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; + SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; + SPI_InitStructure.SPI_CRCPolynomial = 7; + SPI_InitStructure.SPI_Mode = SPI_Mode_Master; + SPI_Init(LIS302DL_SPI, &SPI_InitStructure); + + /* Enable SPI1 */ + SPI_Cmd(LIS302DL_SPI, ENABLE); + + /* Configure GPIO PIN for Lis Chip select */ + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_CS_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(LIS302DL_SPI_CS_GPIO_PORT, &GPIO_InitStructure); + + /* Deselect : Chip Select high */ + GPIO_SetBits(LIS302DL_SPI_CS_GPIO_PORT, LIS302DL_SPI_CS_PIN); + + /* Configure GPIO PINs to detect Interrupts */ + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_INT1_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(LIS302DL_SPI_INT1_GPIO_PORT, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = LIS302DL_SPI_INT2_PIN; + GPIO_Init(LIS302DL_SPI_INT2_GPIO_PORT, &GPIO_InitStructure); +} + +/** + * @brief Sends a Byte through the SPI interface and return the Byte received + * from the SPI bus. + * @param Byte : Byte send. + * @retval The received byte value + */ +static uint8_t LIS302DL_SendByte(uint8_t byte) +{ + /* Loop while DR register in not emplty */ + LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT; + while (SPI_I2S_GetFlagStatus(LIS302DL_SPI, SPI_I2S_FLAG_TXE) == RESET) + { + if((LIS302DLTimeout--) == 0) return LIS302DL_TIMEOUT_UserCallback(); + } + + /* Send a Byte through the SPI peripheral */ + SPI_I2S_SendData(LIS302DL_SPI, byte); + + /* Wait to receive a Byte */ + LIS302DLTimeout = LIS302DL_FLAG_TIMEOUT; + while (SPI_I2S_GetFlagStatus(LIS302DL_SPI, SPI_I2S_FLAG_RXNE) == RESET) + { + if((LIS302DLTimeout--) == 0) return LIS302DL_TIMEOUT_UserCallback(); + } + + /* Return the Byte read from the SPI bus */ + return (uint8_t)SPI_I2S_ReceiveData(LIS302DL_SPI); +} + +#ifdef USE_DEFAULT_TIMEOUT_CALLBACK +/** + * @brief Basic management of the timeout situation. + * @param None. + * @retval None. + */ +uint32_t LIS302DL_TIMEOUT_UserCallback(void) +{ + /* Block communication and all processes */ + while (1) + { + } +} +#endif /* USE_DEFAULT_TIMEOUT_CALLBACK */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ diff --git a/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.h b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.h new file mode 100644 index 0000000..b99cb80 --- /dev/null +++ b/example/stm32f4/Utilities/STM32F4-Discovery/stm32f4_discovery_lis302dl.h @@ -0,0 +1,772 @@ +/** + ****************************************************************************** + * @file stm32f4_discovery_lis302dl.h + * @author MCD Application Team + * @version V1.0.0 + * @date 19-September-2011 + * @brief This file contains all the functions prototypes for the stm32f4_discovery_lis302dl.c + * firmware driver. + ****************************************************************************** + * @attention + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + *

© COPYRIGHT 2011 STMicroelectronics

+ ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4_DISCOVERY_LIS302DL_H +#define __STM32F4_DISCOVERY_LIS302DL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + #include "stm32f4xx.h" + +/** @addtogroup Utilities + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F4_DISCOVERY_LIS302DL + * @{ + */ + + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Exported_Types + * @{ + */ + +/* LIS302DL struct */ +typedef struct +{ + uint8_t Power_Mode; /* Power-down/Active Mode */ + uint8_t Output_DataRate; /* OUT data rate 100 Hz / 400 Hz */ + uint8_t Axes_Enable; /* Axes enable */ + uint8_t Full_Scale; /* Full scale */ + uint8_t Self_Test; /* Self test */ +}LIS302DL_InitTypeDef; + +/* LIS302DL High Pass Filter struct */ +typedef struct +{ + uint8_t HighPassFilter_Data_Selection; /* Internal filter bypassed or data from internal filter send to output register*/ + uint8_t HighPassFilter_CutOff_Frequency; /* High pass filter cut-off frequency */ + uint8_t HighPassFilter_Interrupt; /* High pass filter enabled for Freefall/WakeUp #1 or #2 */ +}LIS302DL_FilterConfigTypeDef; + +/* LIS302DL Interrupt struct */ +typedef struct +{ + uint8_t Latch_Request; /* Latch interrupt request into CLICK_SRC register*/ + uint8_t SingleClick_Axes; /* Single Click Axes Interrupts */ + uint8_t DoubleClick_Axes; /* Double Click Axes Interrupts */ +}LIS302DL_InterruptConfigTypeDef; + +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Exported_Constants + * @{ + */ + +/* Uncomment the following line to use the default LIS302DL_TIMEOUT_UserCallback() + function implemented in stm32f4_discovery_lis302dl.c file. + LIS302DL_TIMEOUT_UserCallback() function is called whenever a timeout condition + occure during communication (waiting transmit data register empty flag(TXE) + or waiting receive data register is not empty flag (RXNE)). */ +/* #define USE_DEFAULT_TIMEOUT_CALLBACK */ + +/* Maximum Timeout values for flags waiting loops. These timeouts are not based + on accurate values, they just guarantee that the application will not remain + stuck if the SPI communication is corrupted. + You may modify these timeout values depending on CPU frequency and application + conditions (interrupts routines ...). */ +#define LIS302DL_FLAG_TIMEOUT ((uint32_t)0x1000) + +/** + * @brief LIS302DL SPI Interface pins + */ +#define LIS302DL_SPI SPI1 +#define LIS302DL_SPI_CLK RCC_APB2Periph_SPI1 + +#define LIS302DL_SPI_SCK_PIN GPIO_Pin_5 /* PA.05 */ +#define LIS302DL_SPI_SCK_GPIO_PORT GPIOA /* GPIOA */ +#define LIS302DL_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOA +#define LIS302DL_SPI_SCK_SOURCE GPIO_PinSource5 +#define LIS302DL_SPI_SCK_AF GPIO_AF_SPI1 + +#define LIS302DL_SPI_MISO_PIN GPIO_Pin_6 /* PA.6 */ +#define LIS302DL_SPI_MISO_GPIO_PORT GPIOA /* GPIOA */ +#define LIS302DL_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOA +#define LIS302DL_SPI_MISO_SOURCE GPIO_PinSource6 +#define LIS302DL_SPI_MISO_AF GPIO_AF_SPI1 + +#define LIS302DL_SPI_MOSI_PIN GPIO_Pin_7 /* PA.7 */ +#define LIS302DL_SPI_MOSI_GPIO_PORT GPIOA /* GPIOA */ +#define LIS302DL_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA +#define LIS302DL_SPI_MOSI_SOURCE GPIO_PinSource7 +#define LIS302DL_SPI_MOSI_AF GPIO_AF_SPI1 + +#define LIS302DL_SPI_CS_PIN GPIO_Pin_3 /* PE.03 */ +#define LIS302DL_SPI_CS_GPIO_PORT GPIOE /* GPIOE */ +#define LIS302DL_SPI_CS_GPIO_CLK RCC_AHB1Periph_GPIOE + +#define LIS302DL_SPI_INT1_PIN GPIO_Pin_0 /* PE.00 */ +#define LIS302DL_SPI_INT1_GPIO_PORT GPIOE /* GPIOE */ +#define LIS302DL_SPI_INT1_GPIO_CLK RCC_AHB1Periph_GPIOE +#define LIS302DL_SPI_INT1_EXTI_LINE EXTI_Line0 +#define LIS302DL_SPI_INT1_EXTI_PORT_SOURCE EXTI_PortSourceGPIOE +#define LIS302DL_SPI_INT1_EXTI_PIN_SOURCE EXTI_PinSource0 +#define LIS302DL_SPI_INT1_EXTI_IRQn EXTI0_IRQn + +#define LIS302DL_SPI_INT2_PIN GPIO_Pin_1 /* PE.01 */ +#define LIS302DL_SPI_INT2_GPIO_PORT GPIOE /* GPIOE */ +#define LIS302DL_SPI_INT2_GPIO_CLK RCC_AHB1Periph_GPIOE +#define LIS302DL_SPI_INT2_EXTI_LINE EXTI_Line1 +#define LIS302DL_SPI_INT2_EXTI_PORT_SOURCE EXTI_PortSourceGPIOE +#define LIS302DL_SPI_INT2_EXTI_PIN_SOURCE EXTI_PinSource1 +#define LIS302DL_SPI_INT2_EXTI_IRQn EXTI1_IRQn + + +/******************************************************************************/ +/*************************** START REGISTER MAPPING **************************/ +/******************************************************************************/ + +/******************************************************************************* +* WHO_AM_I Register: Device Identification Register +* Read only register +* Default value: 0x3B +*******************************************************************************/ +#define LIS302DL_WHO_AM_I_ADDR 0x0F + +/******************************************************************************* +* CTRL_REG1 Register: Control Register 1 +* Read Write register +* Default value: 0x07 +* 7 DR: Data Rate selection. +* 0 - 100 Hz output data rate +* 1 - 400 Hz output data rate +* 6 PD: Power Down control. +* 0 - power down mode +* 1 - active mode +* 5 FS: Full Scale selection. +* 0 - Typical measurement range 2.3 +* 1 - Typical measurement range 9.2 +* 4:3 STP-STM Self Test Enable: +* STP | STM | mode +* ---------------------------- +* 0 | 0 | Normal mode +* 0 | 1 | Self Test M +* 1 | 0 | Self Test P +* 2 Zen: Z axis enable. +* 0 - Z axis disabled +* 1- Z axis enabled +* 1 Yen: Y axis enable. +* 0 - Y axis disabled +* 1- Y axis enabled +* 0 Xen: X axis enable. +* 0 - X axis disabled +* 1- X axis enabled +********************************************************************************/ +#define LIS302DL_CTRL_REG1_ADDR 0x20 + +/******************************************************************************* +* CTRL_REG2 Regsiter: Control Register 2 +* Read Write register +* Default value: 0x00 +* 7 SIM: SPI Serial Interface Mode Selection. +* 0 - 4 wire interface +* 1 - 3 wire interface +* 6 BOOT: Reboot memory content +* 0 - normal mode +* 1 - reboot memory content +* 5 Reserved +* 4 FDS: Filtered data selection. +* 0 - internal filter bypassed +* 1 - data from internal filter sent to output register +* 3 HP FF_WU2: High pass filter enabled for FreeFall/WakeUp#2. +* 0 - filter bypassed +* 1 - filter enabled +* 2 HP FF_WU1: High pass filter enabled for FreeFall/WakeUp#1. +* 0 - filter bypassed +* 1 - filter enabled +* 1:0 HP coeff2-HP coeff1 High pass filter cut-off frequency (ft) configuration. +* ft= ODR[hz]/6*HP coeff +* HP coeff2 | HP coeff1 | HP coeff +* ------------------------------------------- +* 0 | 0 | 8 +* 0 | 1 | 16 +* 1 | 0 | 32 +* 1 | 1 | 64 +* HP coeff | ft[hz] | ft[hz] | +* |ODR 100Hz | ODR 400Hz | +* -------------------------------------------- +* 00 | 2 | 8 | +* 01 | 1 | 4 | +* 10 | 0.5 | 2 | +* 11 | 0.25 | 1 | +*******************************************************************************/ +#define LIS302DL_CTRL_REG2_ADDR 0x21 + +/******************************************************************************* +* CTRL_REG3 Register: Interrupt Control Register +* Read Write register +* Default value: 0x00 +* 7 IHL active: Interrupt active high/low. +* 0 - active high +* 1 - active low +* 6 PP_OD: push-pull/open-drain. +* 0 - push-pull +* 1 - open-drain +* 5:3 I2_CFG2 - I2_CFG0 Data signal on INT2 pad control bits +* 2:0 I1_CFG2 - I1_CFG0 Data signal on INT1 pad control bits +* I1(2)_CFG2 | I1(2)_CFG1 | I1(2)_CFG0 | INT1(2) Pad +* ---------------------------------------------------------- +* 0 | 0 | 0 | GND +* 0 | 0 | 1 | FreeFall/WakeUp#1 +* 0 | 1 | 0 | FreeFall/WakeUp#2 +* 0 | 1 | 1 | FreeFall/WakeUp#1 or FreeFall/WakeUp#2 +* 1 | 0 | 0 | Data ready +* 1 | 1 | 1 | Click interrupt +*******************************************************************************/ +#define LIS302DL_CTRL_REG3_ADDR 0x22 + +/******************************************************************************* +* HP_FILTER_RESET Register: Dummy register. Reading at this address zeroes +* instantaneously the content of the internal high pass filter. If the high pass +* filter is enabled all three axes are instantaneously set to 0g. +* This allows to overcome the settling time of the high pass filter. +* Read only register +* Default value: Dummy +*******************************************************************************/ +#define LIS302DL_HP_FILTER_RESET_REG_ADDR 0x23 + +/******************************************************************************* +* STATUS_REG Register: Status Register +* Default value: 0x00 +* 7 ZYXOR: X, Y and Z axis data overrun. +* 0: no overrun has occurred +* 1: new data has overwritten the previous one before it was read +* 6 ZOR: Z axis data overrun. +* 0: no overrun has occurred +* 1: new data for Z-axis has overwritten the previous one before it was read +* 5 yOR: y axis data overrun. +* 0: no overrun has occurred +* 1: new data for y-axis has overwritten the previous one before it was read +* 4 XOR: X axis data overrun. +* 0: no overrun has occurred +* 1: new data for X-axis has overwritten the previous one before it was read +* 3 ZYXDA: X, Y and Z axis new data available +* 0: a new set of data is not yet available +* 1: a new set of data is available +* 2 ZDA: Z axis new data available. +* 0: a new set of data is not yet available +* 1: a new data for Z axis is available +* 1 YDA: Y axis new data available +* 0: a new set of data is not yet available +* 1: a new data for Y axis is available +* 0 XDA: X axis new data available +* 0: a new set of data is not yet available +* 1: a new data for X axis is available +*******************************************************************************/ +#define LIS302DL_STATUS_REG_ADDR 0x27 + +/******************************************************************************* +* OUT_X Register: X-axis output Data +* Read only register +* Default value: output +* 7:0 XD7-XD0: X-axis output Data +*******************************************************************************/ +#define LIS302DL_OUT_X_ADDR 0x29 + +/******************************************************************************* +* OUT_Y Register: Y-axis output Data +* Read only register +* Default value: output +* 7:0 YD7-YD0: Y-axis output Data +*******************************************************************************/ +#define LIS302DL_OUT_Y_ADDR 0x2B + +/******************************************************************************* +* OUT_Z Register: Z-axis output Data +* Read only register +* Default value: output +* 7:0 ZD7-ZD0: Z-axis output Data +*******************************************************************************/ +#define LIS302DL_OUT_Z_ADDR 0x2D + +/******************************************************************************* +* FF_WW_CFG_1 Register: Configuration register for Interrupt 1 source. +* Read write register +* Default value: 0x00 +* 7 AOI: AND/OR combination of Interrupt events. +* 0: OR combination of interrupt events +* 1: AND combination of interrupt events +* 6 LIR: Latch/not latch interrupt request +* 0: interrupt request not latched +* 1: interrupt request latched +* 5 ZHIE: Enable interrupt generation on Z high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 4 ZLIE: Enable interrupt generation on Z low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +* 3 YHIE: Enable interrupt generation on Y high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 2 YLIE: Enable interrupt generation on Y low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +* 1 XHIE: Enable interrupt generation on X high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 0 XLIE: Enable interrupt generation on X low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +*******************************************************************************/ +#define LIS302DL_FF_WU_CFG1_REG_ADDR 0x30 + +/******************************************************************************* +* FF_WU_SRC_1 Register: Interrupt 1 source register. +* Reading at this address clears FF_WU_SRC_1 register and the FF, WU 1 interrupt +* and allow the refreshment of data in the FF_WU_SRC_1 register if the latched option +* was chosen. +* Read only register +* Default value: 0x00 +* 7 Reserved +* 6 IA: Interrupt active. +* 0: no interrupt has been generated +* 1: one or more interrupts have been generated +* 5 ZH: Z high. +* 0: no interrupt +* 1: ZH event has occurred +* 4 ZL: Z low. +* 0: no interrupt +* 1: ZL event has occurred +* 3 YH: Y high. +* 0: no interrupt +* 1: YH event has occurred +* 2 YL: Y low. +* 0: no interrupt +* 1: YL event has occurred +* 1 YH: X high. +* 0: no interrupt +* 1: XH event has occurred +* 0 YL: X low. +* 0: no interrupt +* 1: XL event has occurred +*******************************************************************************/ +#define LIS302DL_FF_WU_SRC1_REG_ADDR 0x31 + +/******************************************************************************* +* FF_WU_THS_1 Register: Threshold register +* Read Write register +* Default value: 0x00 +* 7 DCRM: Reset mode selection. +* 0 - counter resetted +* 1 - counter decremented +* 6 THS6-THS0: Free-fall/wake-up threshold value. +*******************************************************************************/ +#define LIS302DL_FF_WU_THS1_REG_ADDR 0x32 + +/******************************************************************************* +* FF_WU_DURATION_1 Register: duration Register +* Read Write register +* Default value: 0x00 +* 7:0 D7-D0 Duration value. (Duration steps and maximum values depend on the ODR chosen) + ******************************************************************************/ +#define LIS302DL_FF_WU_DURATION1_REG_ADDR 0x33 + +/******************************************************************************* +* FF_WW_CFG_2 Register: Configuration register for Interrupt 2 source. +* Read write register +* Default value: 0x00 +* 7 AOI: AND/OR combination of Interrupt events. +* 0: OR combination of interrupt events +* 1: AND combination of interrupt events +* 6 LIR: Latch/not latch interrupt request +* 0: interrupt request not latched +* 1: interrupt request latched +* 5 ZHIE: Enable interrupt generation on Z high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 4 ZLIE: Enable interrupt generation on Z low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +* 3 YHIE: Enable interrupt generation on Y high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 2 YLIE: Enable interrupt generation on Y low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +* 1 XHIE: Enable interrupt generation on X high event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value higher than preset threshold +* 0 XLIE: Enable interrupt generation on X low event. +* 0: disable interrupt request +* 1: enable interrupt request on measured accel. value lower than preset threshold +*******************************************************************************/ +#define LIS302DL_FF_WU_CFG2_REG_ADDR 0x34 + +/******************************************************************************* +* FF_WU_SRC_2 Register: Interrupt 2 source register. +* Reading at this address clears FF_WU_SRC_2 register and the FF, WU 2 interrupt +* and allow the refreshment of data in the FF_WU_SRC_2 register if the latched option +* was chosen. +* Read only register +* Default value: 0x00 +* 7 Reserved +* 6 IA: Interrupt active. +* 0: no interrupt has been generated +* 1: one or more interrupts have been generated +* 5 ZH: Z high. +* 0: no interrupt +* 1: ZH event has occurred +* 4 ZL: Z low. +* 0: no interrupt +* 1: ZL event has occurred +* 3 YH: Y high. +* 0: no interrupt +* 1: YH event has occurred +* 2 YL: Y low. +* 0: no interrupt +* 1: YL event has occurred +* 1 YH: X high. +* 0: no interrupt +* 1: XH event has occurred +* 0 YL: X low. +* 0: no interrupt +* 1: XL event has occurred +*******************************************************************************/ +#define LIS302DL_FF_WU_SRC2_REG_ADDR 0x35 + +/******************************************************************************* +* FF_WU_THS_2 Register: Threshold register +* Read Write register +* Default value: 0x00 +* 7 DCRM: Reset mode selection. +* 0 - counter resetted +* 1 - counter decremented +* 6 THS6-THS0: Free-fall/wake-up threshold value. +*******************************************************************************/ +#define LIS302DL_FF_WU_THS2_REG_ADDR 0x36 + +/******************************************************************************* +* FF_WU_DURATION_2 Register: duration Register +* Read Write register +* Default value: 0x00 +* 7:0 D7-D0 Duration value. (Duration steps and maximum values depend on the ODR chosen) + ******************************************************************************/ +#define LIS302DL_FF_WU_DURATION2_REG_ADDR 0x37 + +/****************************************************************************** +* CLICK_CFG Register: click Register +* Read Write register +* Default value: 0x00 +* 7 Reserved +* 6 LIR: Latch Interrupt request. +* 0: interrupt request not latched +* 1: interrupt request latched +* 5 Double_Z: Enable interrupt generation on double click event on Z axis. +* 0: disable interrupt request +* 1: enable interrupt request +* 4 Single_Z: Enable interrupt generation on single click event on Z axis. +* 0: disable interrupt request +* 1: enable interrupt request +* 3 Double_Y: Enable interrupt generation on double click event on Y axis. +* 0: disable interrupt request +* 1: enable interrupt request +* 2 Single_Y: Enable interrupt generation on single click event on Y axis. +* 0: disable interrupt request +* 1: enable interrupt request +* 1 Double_X: Enable interrupt generation on double click event on X axis. +* 0: disable interrupt request +* 1: enable interrupt request +* 0 Single_y: Enable interrupt generation on single click event on X axis. +* 0: disable interrupt request +* 1: enable interrupt request + ******************************************************************************/ +#define LIS302DL_CLICK_CFG_REG_ADDR 0x38 + +/****************************************************************************** +* CLICK_SRC Register: click status Register +* Read only register +* Default value: 0x00 +* 7 Reserved +* 6 IA: Interrupt active. +* 0: no interrupt has been generated +* 1: one or more interrupts have been generated +* 5 Double_Z: Double click on Z axis event. +* 0: no interrupt +* 1: Double Z event has occurred +* 4 Single_Z: Z low. +* 0: no interrupt +* 1: Single Z event has occurred +* 3 Double_Y: Y high. +* 0: no interrupt +* 1: Double Y event has occurred +* 2 Single_Y: Y low. +* 0: no interrupt +* 1: Single Y event has occurred +* 1 Double_X: X high. +* 0: no interrupt +* 1: Double X event has occurred +* 0 Single_X: X low. +* 0: no interrupt +* 1: Single X event has occurred +*******************************************************************************/ +#define LIS302DL_CLICK_SRC_REG_ADDR 0x39 + +/******************************************************************************* +* CLICK_THSY_X Register: Click threshold Y and X register +* Read Write register +* Default value: 0x00 +* 7:4 THSy3-THSy0: Click threshold on Y axis, step 0.5g +* 3:0 THSx3-THSx0: Click threshold on X axis, step 0.5g +*******************************************************************************/ +#define LIS302DL_CLICK_THSY_X_REG_ADDR 0x3B + +/******************************************************************************* +* CLICK_THSZ Register: Click threshold Z register +* Read Write register +* Default value: 0x00 +* 7:4 Reserved +* 3:0 THSz3-THSz0: Click threshold on Z axis, step 0.5g +*******************************************************************************/ +#define LIS302DL_CLICK_THSZ_REG_ADDR 0x3C + +/******************************************************************************* +* CLICK_TimeLimit Register: Time Limit register +* Read Write register +* Default value: 0x00 +* 7:0 Dur7-Dur0: Time Limit value, step 0.5g +*******************************************************************************/ +#define LIS302DL_CLICK_TIMELIMIT_REG_ADDR 0x3D + +/******************************************************************************* +* CLICK_Latency Register: Latency register +* Read Write register +* Default value: 0x00 +* 7:0 Lat7-Lat0: Latency value, step 1msec +*******************************************************************************/ +#define LIS302DL_CLICK_LATENCY_REG_ADDR 0x3E + +/******************************************************************************* +* CLICK_Window Register: Window register +* Read Write register +* Default value: 0x00 +* 7:0 Win7-Win0: Window value, step 1msec +*******************************************************************************/ +#define LIS302DL_CLICK_WINDOW_REG_ADDR 0x3F + +/******************************************************************************/ +/**************************** END REGISTER MAPPING ***************************/ +/******************************************************************************/ + +#define LIS302DL_SENSITIVITY_2_3G 18 /* 18 mg/digit*/ +#define LIS302DL_SENSITIVITY_9_2G 72 /* 72 mg/digit*/ + +/** @defgroup Data_Rate_selection + * @{ + */ +#define LIS302DL_DATARATE_100 ((uint8_t)0x00) +#define LIS302DL_DATARATE_400 ((uint8_t)0x80) +/** + * @} + */ + +/** @defgroup Power_Mode_selection + * @{ + */ +#define LIS302DL_LOWPOWERMODE_POWERDOWN ((uint8_t)0x00) +#define LIS302DL_LOWPOWERMODE_ACTIVE ((uint8_t)0x40) +/** + * @} + */ + +/** @defgroup Full_Scale_selection + * @{ + */ +#define LIS302DL_FULLSCALE_2_3 ((uint8_t)0x00) +#define LIS302DL_FULLSCALE_9_2 ((uint8_t)0x20) +/** + * @} + */ + +/** @defgroup Self_Test_selection + * @{ + */ +#define LIS302DL_SELFTEST_NORMAL ((uint8_t)0x00) +#define LIS302DL_SELFTEST_P ((uint8_t)0x10) +#define LIS302DL_SELFTEST_M ((uint8_t)0x08) +/** + * @} + */ + +/** @defgroup Direction_XYZ_selection + * @{ + */ +#define LIS302DL_X_ENABLE ((uint8_t)0x01) +#define LIS302DL_Y_ENABLE ((uint8_t)0x02) +#define LIS302DL_Z_ENABLE ((uint8_t)0x04) +#define LIS302DL_XYZ_ENABLE ((uint8_t)0x07) +/** + * @} + */ + + /** @defgroup SPI_Serial_Interface_Mode_selection + * @{ + */ +#define LIS302DL_SERIALINTERFACE_4WIRE ((uint8_t)0x00) +#define LIS302DL_SERIALINTERFACE_3WIRE ((uint8_t)0x80) +/** + * @} + */ + + /** @defgroup Boot_Mode_selection + * @{ + */ +#define LIS302DL_BOOT_NORMALMODE ((uint8_t)0x00) +#define LIS302DL_BOOT_REBOOTMEMORY ((uint8_t)0x40) +/** + * @} + */ + + /** @defgroup Filtered_Data_Selection_Mode_selection + * @{ + */ +#define LIS302DL_FILTEREDDATASELECTION_BYPASSED ((uint8_t)0x00) +#define LIS302DL_FILTEREDDATASELECTION_OUTPUTREGISTER ((uint8_t)0x20) +/** + * @} + */ + + /** @defgroup High_Pass_Filter_Interrupt_selection + * @{ + */ +#define LIS302DL_HIGHPASSFILTERINTERRUPT_OFF ((uint8_t)0x00) +#define LIS302DL_HIGHPASSFILTERINTERRUPT_1 ((uint8_t)0x04) +#define LIS302DL_HIGHPASSFILTERINTERRUPT_2 ((uint8_t)0x08) +#define LIS302DL_HIGHPASSFILTERINTERRUPT_1_2 ((uint8_t)0x0C) +/** + * @} + */ + + /** @defgroup High_Pass_Filter_selection + * @{ + */ +#define LIS302DL_HIGHPASSFILTER_LEVEL_0 ((uint8_t)0x00) +#define LIS302DL_HIGHPASSFILTER_LEVEL_1 ((uint8_t)0x01) +#define LIS302DL_HIGHPASSFILTER_LEVEL_2 ((uint8_t)0x02) +#define LIS302DL_HIGHPASSFILTER_LEVEL_3 ((uint8_t)0x03) +/** + * @} + */ + + +/** @defgroup latch_Interrupt_Request_selection + * @{ + */ +#define LIS302DL_INTERRUPTREQUEST_NOTLATCHED ((uint8_t)0x00) +#define LIS302DL_INTERRUPTREQUEST_LATCHED ((uint8_t)0x40) +/** + * @} + */ + +/** @defgroup Click_Interrupt_XYZ_selection + * @{ + */ +#define LIS302DL_CLICKINTERRUPT_XYZ_DISABLE ((uint8_t)0x00) +#define LIS302DL_CLICKINTERRUPT_X_ENABLE ((uint8_t)0x01) +#define LIS302DL_CLICKINTERRUPT_Y_ENABLE ((uint8_t)0x04) +#define LIS302DL_CLICKINTERRUPT_Z_ENABLE ((uint8_t)0x10) +#define LIS302DL_CLICKINTERRUPT_XYZ_ENABLE ((uint8_t)0x15) +/** + * @} + */ + +/** @defgroup Double_Click_Interrupt_XYZ_selection + * @{ + */ +#define LIS302DL_DOUBLECLICKINTERRUPT_XYZ_DISABLE ((uint8_t)0x00) +#define LIS302DL_DOUBLECLICKINTERRUPT_X_ENABLE ((uint8_t)0x02) +#define LIS302DL_DOUBLECLICKINTERRUPT_Y_ENABLE ((uint8_t)0x08) +#define LIS302DL_DOUBLECLICKINTERRUPT_Z_ENABLE ((uint8_t)0x20) +#define LIS302DL_DOUBLECLICKINTERRUPT_XYZ_ENABLE ((uint8_t)0x2A) +/** + * @} + */ +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Exported_Macros + * @{ + */ +#define LIS302DL_CS_LOW() GPIO_ResetBits(LIS302DL_SPI_CS_GPIO_PORT, LIS302DL_SPI_CS_PIN) +#define LIS302DL_CS_HIGH() GPIO_SetBits(LIS302DL_SPI_CS_GPIO_PORT, LIS302DL_SPI_CS_PIN) +/** + * @} + */ + +/** @defgroup STM32F4_DISCOVERY_LIS302DL_Exported_Functions + * @{ + */ +void LIS302DL_Init(LIS302DL_InitTypeDef *LIS302DL_InitStruct); +void LIS302DL_InterruptConfig(LIS302DL_InterruptConfigTypeDef *LIS302DL_InterruptConfigStruct); +void LIS302DL_FilterConfig(LIS302DL_FilterConfigTypeDef *LIS302DL_FilterConfigStruct); +void LIS302DL_LowpowerCmd(uint8_t LowPowerMode); +void LIS302DL_FullScaleCmd(uint8_t FS_value); +void LIS302DL_DataRateCmd(uint8_t DataRateValue); +void LIS302DL_RebootCmd(void); +void LIS302DL_ReadACC(int32_t* out); +void LIS302DL_Write(uint8_t* pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite); +void LIS302DL_Read(uint8_t* pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead); + +/* USER Callbacks: This is function for which prototype only is declared in + MEMS accelerometre driver and that should be implemented into user applicaiton. */ +/* LIS302DL_TIMEOUT_UserCallback() function is called whenever a timeout condition + occure during communication (waiting transmit data register empty flag(TXE) + or waiting receive data register is not empty flag (RXNE)). + You can use the default timeout callback implementation by uncommenting the + define USE_DEFAULT_TIMEOUT_CALLBACK in stm32f4_discovery_lis302dl.h file. + Typically the user implementation of this callback should reset MEMS peripheral + and re-initialize communication or in worst case reset all the application. */ +uint32_t LIS302DL_TIMEOUT_UserCallback(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4_DISCOVERY_LIS302DL_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/