BLE shield

Fork of X_NUCLEO_IDB0XA1 by ST

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers stm32_bluenrg_ble_dma_lp.c Source File

stm32_bluenrg_ble_dma_lp.c

Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32_bluenrg_ble_dma_lp.c
00004   * @author  CL
00005   * @version V1.0.0
00006   * @date    04-July-2014
00007   * @brief   
00008   ******************************************************************************
00009   * @attention
00010   *
00011   * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
00012   *
00013   * Redistribution and use in source and binary forms, with or without modification,
00014   * are permitted provided that the following conditions are met:
00015   *   1. Redistributions of source code must retain the above copyright notice,
00016   *      this list of conditions and the following disclaimer.
00017   *   2. Redistributions in binary form must reproduce the above copyright notice,
00018   *      this list of conditions and the following disclaimer in the documentation
00019   *      and/or other materials provided with the distribution.
00020   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00021   *      may be used to endorse or promote products derived from this software
00022   *      without specific prior written permission.
00023   *
00024   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00025   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00028   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00030   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034   *
00035   ******************************************************************************
00036   */ 
00037 
00038 // ANDREA -- FIXME: to exclude from building when DMA is disabled
00039 #ifdef __DMA_LP__
00040 
00041 /* Includes ------------------------------------------------------------------*/
00042 #include "stm32_bluenrg_ble_dma_lp.h "
00043 #include "hci_const.h"
00044 
00045 /** @addtogroup BSP
00046  *  @{
00047  */
00048 
00049 /** @addtogroup X-NUCLEO-IDB04A1
00050  *  @{
00051  */
00052 
00053 /** @defgroup STM32_BLUENRG_BLE_DMA_LP
00054  *  @{
00055  */
00056 
00057 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Private_Defines 
00058  *  @{
00059  */
00060  
00061 #define TEST_TX_BUFFER_LIMITATION 0
00062 #define MAX_TX_BUFFER_SIZE 0x7F
00063 #define BLUENRG_READY_STATE 0x02
00064 
00065 #define HEADER_SIZE 5
00066 #define MAX_BUFFER_SIZE 255
00067 
00068 /**
00069  * @}
00070  */
00071  
00072 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Private_Types
00073 * @{
00074 */ 
00075 
00076 typedef enum
00077 {
00078   SPI_HEADER_TRANSMIT,
00079   SPI_PAYLOAD_TRANSMIT
00080 } SPI_TRANSMIT_REQUEST_t;
00081 
00082 typedef enum
00083 {
00084   SPI_HEADER_TRANSMITTED,
00085   SPI_PAYLOAD_TRANSMITTED
00086 } SPI_TRANSMIT_EVENT_t;
00087 
00088 typedef enum
00089 {
00090   SPI_REQUEST_VALID_HEADER_FOR_RX,
00091   SPI_REQUEST_VALID_HEADER_FOR_TX,
00092   SPI_REQUEST_PAYLOAD
00093 } SPI_RECEIVE_REQUEST_t;
00094 
00095 typedef enum
00096 {
00097   SPI_CHECK_RECEIVED_HEADER_FOR_RX,
00098   SPI_CHECK_RECEIVED_HEADER_FOR_TX,
00099   SPI_RECEIVE_END
00100 } SPI_RECEIVE_EVENT_t;
00101 
00102 typedef enum
00103 {
00104   SPI_AVAILABLE,
00105   SPI_BUSY
00106 } SPI_PERIPHERAL_STATUS_t;
00107 
00108 typedef struct
00109 {
00110   SPI_TRANSMIT_EVENT_t Spi_Transmit_Event;
00111   uint8_t* header_data;
00112   uint8_t* payload_data;
00113   uint8_t header_size;
00114   uint8_t payload_size;
00115   uint8_t payload_size_to_transmit;
00116   uint8_t packet_cont;
00117   uint8_t RequestPending;
00118 } SPI_Transmit_Context_t;
00119 
00120 typedef struct
00121 {
00122   SPI_RECEIVE_EVENT_t Spi_Receive_Event;
00123   uint16_t payload_len;
00124   uint8_t* buffer;
00125   uint8_t buffer_size;
00126 } SPI_Receive_Context_t;
00127 
00128 typedef struct
00129 {
00130   SPI_HandleTypeDef *hspi;
00131   SPI_PERIPHERAL_STATUS_t Spi_Peripheral_State;
00132   SPI_Receive_Context_t SPI_Receive_Context;
00133   SPI_Transmit_Context_t SPI_Transmit_Context;
00134 } SPI_Context_t;
00135 
00136 /**
00137  * @}
00138  */
00139 
00140 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Private_Variables
00141  * @{
00142  */
00143 
00144 SPI_HandleTypeDef SpiHandle;
00145 SPI_Context_t SPI_Context;
00146 
00147 const uint8_t Write_Header_CMD[HEADER_SIZE] = {0x0a, 0x00, 0x00, 0x00, 0x00};
00148 const uint8_t Read_Header_CMD[HEADER_SIZE] = {0x0b, 0x00, 0x00, 0x00, 0x00};
00149 const uint8_t dummy_bytes = 0xFF;
00150 
00151 uint8_t Received_Header[HEADER_SIZE];
00152 
00153 #ifdef ENABLE_SPI_FIX
00154 static uint8_t StartupTimerId;
00155 #endif
00156 static uint8_t TxRxTimerId;
00157 volatile uint8_t ubnRFresetTimerLock;
00158 pf_TIMER_TimerCallBack_t pTimerTxRxCallback;
00159 
00160 /**
00161  * @}
00162  */
00163 
00164 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Extern_Variables
00165  * @{
00166  */
00167 extern uint8_t* HCI_read_packet;
00168 
00169 /**
00170  * @}
00171  */
00172 
00173 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Private_Function_Prototypes 
00174  *  @{
00175  */
00176  
00177 /* Private function prototypes -----------------------------------------------*/
00178 static void SPI_Transmit_Manager(SPI_TRANSMIT_REQUEST_t TransmitRequest);
00179 static void SPI_Receive_Manager(SPI_RECEIVE_REQUEST_t ReceiveRequest);
00180 static void set_irq_as_output(void);
00181 static void set_irq_as_input(void);
00182 static void Disable_SPI_Receiving_Path(void);
00183 static void Enable_SPI_Receiving_Path(void);
00184 static void Enable_SPI_CS(void);
00185 static void Disable_SPI_CS(void);
00186 static void DisableEnable_SPI_CS(void);
00187 static void TransmitClosure(void);
00188 static void ReceiveClosure(void);
00189 static void ReceiveHeader(SPI_RECEIVE_EVENT_t ReceiveEvent, uint8_t * DataHeader);
00190 static void WakeupBlueNRG(void);
00191 static void TimerStartupCallback(void);
00192 static void TimerTransmitCallback(void);
00193 static void pf_nRFResetTimerCallBack(void);
00194 static void TimerTxRxCallback(void);
00195 static void ProcessEndOfReceive(void);
00196 
00197 /**
00198  * @}
00199  */
00200 
00201 /** @defgroup STM32_BLUENRG_BLE_DMA_LP_Exported_Functions 
00202  * @{
00203  */ 
00204  
00205 /**
00206  * @brief  This function notify when then BlueNRG nRESET may be released
00207  * @param  None
00208  * @retval None
00209  */
00210 static void pf_nRFResetTimerCallBack(void)
00211 {
00212   ubnRFresetTimerLock = 0;
00213   
00214   return;
00215 }
00216 
00217 /**
00218  * @brief  Timer callback to handle RxTx Timers
00219  * @param  None
00220  * @retval None
00221  */
00222 static void TimerTxRxCallback(void)
00223 {
00224   pTimerTxRxCallback();
00225   
00226   return;
00227 }
00228 
00229 /**
00230  * @brief  Close the receiver path
00231  * @param  None
00232  * @retval None
00233  */
00234 static void ReceiveClosure(void)
00235 {
00236   /*
00237    *  Disable both DMA
00238    */
00239   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmatx);
00240   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmarx);
00241   
00242   /*
00243    * Check if a command is pending
00244    */
00245   __disable_irq();
00246   if(SPI_Context.SPI_Transmit_Context.RequestPending == TRUE)
00247   {
00248     SPI_Context.SPI_Transmit_Context.RequestPending = FALSE;
00249     SPI_Context.Spi_Peripheral_State = SPI_BUSY;
00250     Disable_SPI_Receiving_Path();
00251     __enable_irq();
00252     WakeupBlueNRG();
00253   }
00254   else
00255   {
00256     SPI_Context.Spi_Peripheral_State = SPI_AVAILABLE;
00257     __enable_irq();
00258   }
00259   
00260   return;
00261 }
00262 
00263 /**
00264  * @brief  Delay Notification to the App to prevent dummy event read
00265  * @param  None
00266  * @retval None
00267  */
00268 static void ProcessEndOfReceive(void)
00269 {
00270   ReceiveClosure();
00271   
00272   HCI_Isr(HCI_read_packet, SPI_Context.SPI_Receive_Context.payload_len);
00273   
00274   return;
00275 }
00276 
00277 /**
00278  * @brief  Timer callback to apply timeout SPI FIX
00279  * @param  None
00280  * @retval None
00281  */
00282 static void TimerTransmitCallback(void)
00283 {
00284   SPI_Receive_Manager(SPI_REQUEST_VALID_HEADER_FOR_TX); /**< BlueNRG not ready for writing */
00285   LPM_Mode_Request(eLPM_SPI_TX, eLPM_Mode_Sleep);
00286   
00287   return;
00288 }
00289 
00290 /**
00291  * @brief  Closes the SPI when BLE is disabled by the application
00292  *         Releases allocated resources
00293  * @param  None
00294  * @retval None
00295  */
00296 void BNRG_SPI_Close(void)
00297 {
00298 #ifdef ENABLE_SPI_FIX
00299   TIMER_Delete(StartupTimerId);
00300 #endif
00301   TIMER_Delete(TxRxTimerId);
00302   
00303   return;
00304 }
00305 
00306 /**
00307  * @brief  Initializes the SPI communication with the BlueNRG Shield.
00308  * @param  None
00309  * @retval None
00310  */
00311 void BNRG_SPI_Init(void)
00312 {
00313   BNRG_MSP_SPI_Init(&SpiHandle);
00314   
00315   SPI_Context.hspi = &SpiHandle;  
00316   
00317   SPI_Context.Spi_Peripheral_State = SPI_AVAILABLE;
00318   SPI_Context.SPI_Transmit_Context.RequestPending = FALSE;
00319   
00320   __HAL_BLUENRG_SPI_ENABLE_DMAREQ(&SpiHandle, SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN);
00321   
00322   __HAL_SPI_ENABLE(&SpiHandle);
00323 
00324 #ifdef ENABLE_SPI_FIX
00325   TIMER_Create(eTimerModuleID_Interrupt, &StartupTimerId, eTimerMode_SingleShot, TimerStartupCallback);
00326 #endif
00327   TIMER_Create(eTimerModuleID_Interrupt, &TxRxTimerId, eTimerMode_SingleShot, TimerTxRxCallback);
00328   return;
00329 }
00330 
00331 /**
00332  * @brief  Initializes the SPI communication with the BlueNRG Shield
00333  * @param  None
00334  * @retval None
00335  */
00336 void BNRG_MSP_SPI_Init(SPI_HandleTypeDef * hspi)
00337 {
00338   hspi->Instance = BNRG_SPI_INSTANCE;
00339   hspi->Init.Mode = BNRG_SPI_MODE;
00340   hspi->Init.Direction = BNRG_SPI_DIRECTION;
00341   hspi->Init.DataSize = BNRG_SPI_DATASIZE;
00342   hspi->Init.CLKPolarity = BNRG_SPI_CLKPOLARITY;
00343   hspi->Init.CLKPhase = BNRG_SPI_CLKPHASE;
00344   hspi->Init.NSS = BNRG_SPI_NSS;
00345   hspi->Init.FirstBit = BNRG_SPI_FIRSTBIT;
00346   hspi->Init.TIMode = BNRG_SPI_TIMODE;
00347   hspi->Init.CRCPolynomial = BNRG_SPI_CRCPOLYNOMIAL;
00348   hspi->Init.BaudRatePrescaler = BNRG_SPI_BAUDRATEPRESCALER;
00349   hspi->Init.CRCCalculation = BNRG_SPI_CRCCALCULATION;
00350 
00351   HAL_SPI_Init(hspi);
00352 
00353   return;
00354 }
00355 
00356 /**
00357  * @brief  Resets the BlueNRG.
00358  * @param  None
00359  * @retval None
00360  */
00361 void BlueNRG_RST(void)
00362 {
00363   uint8_t ubnRFResetTimerID;
00364   
00365   GPIO_InitTypeDef GPIO_InitStruct;
00366   
00367   GPIO_InitStruct.Pin = BNRG_SPI_RESET_PIN;
00368   GPIO_InitStruct.Speed = BNRG_SPI_RESET_SPEED;
00369   TIMER_Create(eTimerModuleID_Interrupt, &ubnRFResetTimerID, eTimerMode_SingleShot, pf_nRFResetTimerCallBack);
00370   
00371   BNRG_SPI_RESET_CLK_ENABLE();
00372   
00373   HAL_GPIO_WritePin(BNRG_SPI_RESET_PORT, BNRG_SPI_RESET_PIN, GPIO_PIN_RESET);
00374   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
00375   GPIO_InitStruct.Pull = GPIO_NOPULL;
00376   HAL_GPIO_Init(BNRG_SPI_RESET_PORT, &GPIO_InitStruct);
00377   
00378   TIMER_Start(ubnRFResetTimerID, BLUENRG_HOLD_TIME_IN_RESET);
00379   ubnRFresetTimerLock = 1;
00380   while(ubnRFresetTimerLock == 1);
00381   
00382   HAL_GPIO_WritePin(BNRG_SPI_RESET_PORT, BNRG_SPI_RESET_PIN, GPIO_PIN_SET);
00383   
00384 #if 1
00385   /*
00386    * Limitation in HAL V1.1.0
00387    * The HAL_GPIO_Init() is first configuring the Mode of the IO before the Pull UP configuration
00388    * To avoid glitch on the IO, the configuration shall go through an extra step OUTPUT/PULLUP
00389    * to set upfront the PULL UP configuration.
00390    */
00391   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
00392   GPIO_InitStruct.Pull = GPIO_PULLUP;
00393   HAL_GPIO_Init(BNRG_SPI_RESET_PORT, &GPIO_InitStruct);
00394 #endif
00395   
00396   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
00397   GPIO_InitStruct.Pull = GPIO_PULLUP;
00398   HAL_GPIO_Init(BNRG_SPI_RESET_PORT, &GPIO_InitStruct);
00399   
00400   TIMER_Start(ubnRFResetTimerID, BLUENRG_HOLD_TIME_AFTER_RESET);
00401   ubnRFresetTimerLock = 1;
00402   while(ubnRFresetTimerLock == 1);
00403   TIMER_Delete(ubnRFResetTimerID);
00404   
00405   return;
00406 }
00407 
00408 /**
00409  * @brief  Writes data from local buffer to SPI.
00410  * @param  hspi: SPI handle
00411  * @param  header_data: First data buffer to be written
00412  * @param  payload_data: Second data buffer to be written
00413  * @param  header_size: Size of first data buffer to be written
00414  * @param  payload_size: Size of second data buffer to be written
00415  * @retval Number of read bytes
00416  */
00417 void BlueNRG_SPI_Write(uint8_t* header_data, uint8_t* payload_data, uint8_t header_size, uint8_t payload_size)
00418 {  
00419   SPI_Context.SPI_Transmit_Context.header_data = header_data;
00420   SPI_Context.SPI_Transmit_Context.payload_data = payload_data;
00421   SPI_Context.SPI_Transmit_Context.header_size = header_size;
00422   SPI_Context.SPI_Transmit_Context.payload_size = payload_size;
00423   
00424   SPI_Context.SPI_Transmit_Context.packet_cont = FALSE;
00425   
00426   __disable_irq();
00427   if(SPI_Context.Spi_Peripheral_State == SPI_AVAILABLE)
00428   {
00429     SPI_Context.Spi_Peripheral_State = SPI_BUSY;
00430     Disable_SPI_Receiving_Path();
00431     __enable_irq();
00432     WakeupBlueNRG();
00433   }
00434   else
00435   {
00436     SPI_Context.SPI_Transmit_Context.RequestPending = TRUE;
00437     __enable_irq();
00438   }
00439   
00440   return;
00441 }
00442 
00443 /**
00444  * @brief  Set in Output mode the IRQ.
00445  * @param  None
00446  * @retval None
00447  */
00448 static void set_irq_as_output(void)
00449 {
00450   HAL_GPIO_WritePin(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN, GPIO_PIN_SET);
00451   HAL_LPPUART_GPIO_Set_Mode(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN_POSITION, GPIO_MODE_OUTPUT_PP);
00452   __HAL_GPIO_EXTI_CLEAR_IT(BNRG_SPI_IRQ_PIN);
00453 }
00454 
00455 /**
00456  * @brief  Set the IRQ in input mode.
00457  * @param  None
00458  * @retval None
00459  */
00460 static void set_irq_as_input(void)
00461 {
00462   HAL_GPIO_WritePin(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN, GPIO_PIN_RESET); // WARNING: it may conflict with BlueNRG driving High
00463   HAL_LPPUART_GPIO_Set_Mode(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN_POSITION, GPIO_MODE_INPUT);
00464 }
00465 
00466 /**
00467  * @brief  Enable SPI IRQ.
00468  * @param  None
00469  * @retval None
00470  */
00471 static void Enable_SPI_Receiving_Path(void)
00472 {  
00473   __HAL_GPIO_EXTI_CLEAR_IT(BNRG_SPI_EXTI_PIN);
00474   HAL_NVIC_ClearPendingIRQ(BNRG_SPI_EXTI_IRQn);
00475   HAL_NVIC_EnableIRQ(BNRG_SPI_EXTI_IRQn);
00476   
00477   if (HAL_GPIO_ReadPin(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN) == GPIO_PIN_SET)
00478   {
00479     __HAL_GPIO_EXTI_GENERATE_SWIT(BNRG_SPI_IRQ_PIN);
00480   }
00481 }
00482 
00483 /**
00484  * @brief  Disable SPI IRQ.
00485  * @param  None
00486  * @retval None
00487  */
00488 static void Disable_SPI_Receiving_Path(void)
00489 {  
00490   HAL_NVIC_DisableIRQ(BNRG_SPI_EXTI_IRQn);
00491 }
00492 
00493 /**
00494  * @brief  Enable SPI CS.
00495  * @param  None
00496  * @retval None
00497  */
00498 static void Enable_SPI_CS(void)
00499 {
00500   /* CS reset */
00501   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_RESET);
00502 }
00503 
00504 /**
00505  * @brief  Disable SPI CS.
00506  * @param  None
00507  * @retval None
00508  */
00509 static void Disable_SPI_CS(void)
00510 {
00511   while (__HAL_SPI_GET_FLAG(SPI_Context.hspi,SPI_FLAG_BSY) == SET);
00512   
00513   /* CS set */
00514   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET);
00515 }
00516 
00517 /**
00518  * @brief  Disable and Enable SPI CS.
00519  * @param  None
00520  * @retval None
00521  */
00522 static void DisableEnable_SPI_CS(void)
00523 {
00524   while (__HAL_SPI_GET_FLAG(SPI_Context.hspi,SPI_FLAG_BSY) == SET);
00525   
00526   /* CS set */
00527   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET);
00528   
00529   /* CS reset */
00530   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_RESET);
00531 }
00532 
00533 /**
00534  * @brief Tx and Rx Transfer completed callbacks
00535  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
00536  *              the configuration information for SPI module.
00537  * @retval None
00538  */
00539 void BlueNRG_DMA_RxCallback(void)
00540 {
00541   uint16_t byte_count;
00542   uint8_t ready_state;
00543   
00544   __HAL_DMA_CLEAR_FLAG(SPI_Context.hspi->hdmarx, BNRG_SPI_RX_DMA_TC_FLAG);
00545   
00546   /**
00547    * The TCIF shall be cleared to be able to start a new DMA transmission later on when required.
00548    * When receiving data, the TCIE is not set as there is no need to handle the interrupt
00549    * handler of the DMA_Tx.
00550    * The TCIF clearing is mandatory on STM32F4 but not on STM32L0.
00551    * In order to keep code identical across platform, the TCIF clearing may be kept as well on
00552    * the STM32L0 and all other MCUs.
00553    */
00554   __HAL_DMA_CLEAR_FLAG(SPI_Context.hspi->hdmatx, BNRG_SPI_TX_DMA_TC_FLAG);
00555   switch (SPI_Context.SPI_Receive_Context.Spi_Receive_Event)
00556   {
00557   case SPI_CHECK_RECEIVED_HEADER_FOR_RX:
00558     byte_count = (Received_Header[4]<<8)|Received_Header[3];
00559     ready_state = Received_Header[0];
00560     
00561     if ((byte_count == 0) || (ready_state != BLUENRG_READY_STATE))
00562     {
00563       if (HAL_GPIO_ReadPin(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN) == GPIO_PIN_RESET)
00564       {
00565         /**
00566          * This USE CASE shall never happen as this may break the IRQ/CS specification
00567          * The IRQ line shall never be low when CS is low to avoid BlueNRG race condition when
00568          * entering low power mode
00569          * the SPI_END_RECEIVE_FIX has been implemented to make sure this USE CASE never occurs
00570          * However, even when the behavior is not compliant to the specification, the BlueNRG
00571          * may not fail so it is increasing robustness by adding this checking just in case the
00572          * timeout define in the workaround is too short which will end up to marginally brake
00573          * the specification.
00574          * This checking will poping BluenRG for a dummy even
00575          */
00576         
00577         /* Release CS line */
00578         Disable_SPI_CS();
00579         
00580         LPM_Mode_Request(eLPM_SPI_RX, eLPM_Mode_LP_Stop);
00581         
00582         ReceiveClosure();
00583       }
00584       else
00585       {
00586         DisableEnable_SPI_CS();
00587         SPI_Receive_Manager(SPI_REQUEST_VALID_HEADER_FOR_RX); /**< BlueNRG not ready for reading */
00588       }
00589     }
00590     else
00591     {
00592       SPI_Receive_Manager(SPI_REQUEST_PAYLOAD); /**< BlueNRG is ready for reading */
00593     }
00594     break;
00595     
00596   case SPI_RECEIVE_END:
00597     /* Release CS line */
00598     Disable_SPI_CS();
00599     
00600     LPM_Mode_Request(eLPM_SPI_RX, eLPM_Mode_LP_Stop);
00601     
00602 #if (SPI_END_RECEIVE_FIX == 1)
00603     pTimerTxRxCallback = ProcessEndOfReceive;
00604     TIMER_Start(TxRxTimerId, SPI_END_RECEIVE_FIX_TIMEOUT);
00605 #else
00606     ProcessEndOfReceive();
00607 #endif
00608     break;
00609     
00610   case SPI_CHECK_RECEIVED_HEADER_FOR_TX:
00611     byte_count = (Received_Header[2]<<8)|Received_Header[1];
00612     ready_state = Received_Header[0];
00613     
00614     if ((byte_count == 0) || (ready_state != BLUENRG_READY_STATE))
00615     {
00616       DisableEnable_SPI_CS();
00617       SPI_Receive_Manager(SPI_REQUEST_VALID_HEADER_FOR_TX); /**< BlueNRG not ready for writing */
00618     }
00619     else
00620     {
00621 #if (TEST_TX_BUFFER_LIMITATION == 1)
00622       if(byte_count > MAX_TX_BUFFER_SIZE)
00623       {
00624         byte_count = MAX_TX_BUFFER_SIZE;
00625       }
00626 #endif
00627       
00628       if(SPI_Context.SPI_Transmit_Context.packet_cont != TRUE)
00629       {
00630         if( byte_count < (SPI_Context.SPI_Transmit_Context.header_size + SPI_Context.SPI_Transmit_Context.payload_size))
00631         {
00632           SPI_Context.SPI_Transmit_Context.payload_size_to_transmit = byte_count - SPI_Context.SPI_Transmit_Context.header_size;
00633           SPI_Context.SPI_Transmit_Context.payload_size -= SPI_Context.SPI_Transmit_Context.payload_size_to_transmit;
00634           SPI_Context.SPI_Transmit_Context.packet_cont = TRUE;
00635         }
00636         else
00637         {
00638           SPI_Context.SPI_Transmit_Context.payload_size_to_transmit = SPI_Context.SPI_Transmit_Context.payload_size;
00639         }
00640         
00641         SPI_Transmit_Manager(SPI_HEADER_TRANSMIT);
00642       }
00643       else
00644       {
00645         if( byte_count < SPI_Context.SPI_Transmit_Context.payload_size)
00646         {
00647           SPI_Context.SPI_Transmit_Context.payload_size_to_transmit = byte_count;
00648           SPI_Context.SPI_Transmit_Context.payload_size -= SPI_Context.SPI_Transmit_Context.payload_size_to_transmit;
00649         }
00650         else
00651         {
00652           SPI_Context.SPI_Transmit_Context.payload_size_to_transmit = SPI_Context.SPI_Transmit_Context.payload_size;
00653           SPI_Context.SPI_Transmit_Context.payload_size = 0;
00654         }
00655         
00656         SPI_Transmit_Manager(SPI_PAYLOAD_TRANSMIT);
00657       }
00658     }
00659     
00660     break;
00661     
00662   default:
00663     break;
00664   }
00665 }
00666 
00667 #ifdef ENABLE_SPI_FIX
00668 /**
00669  * @brief  Wakeup BlueNRG
00670  * @param  None
00671  * @retval None
00672  */
00673 static void WakeupBlueNRG(void)
00674 {
00675   Disable_SPI_Receiving_Path();
00676   pTimerTxRxCallback = TimerTransmitCallback;
00677   set_irq_as_output();
00678   TIMER_Start(StartupTimerId, SPI_FIX_TIMEOUT);
00679   TIMER_Start(TxRxTimerId, SPI_FIX_TIMEOUT+SPI_TX_TIMEOUT);
00680   LPM_Mode_Request(eLPM_SPI_TX, eLPM_Mode_LP_Stop);
00681     
00682   return;
00683 }
00684 
00685 /**
00686  * @brief  Timer callback to apply timeout SPI FIX
00687  * @param  None
00688  * @retval None
00689  */
00690 static void TimerStartupCallback(void)
00691 {
00692   Enable_SPI_CS();
00693   
00694   return;
00695 }
00696 
00697 #else
00698 /**
00699  * @brief  Wakeup BlueNRG
00700  * @param  None
00701  * @retval None
00702  */
00703 static void WakeupBlueNRG(void)
00704 {
00705   Disable_SPI_Receiving_Path();
00706   pTimerTxRxCallback = TimerTransmitCallback;
00707   Enable_SPI_CS();
00708   TIMER_Start(TxRxTimerId, SPI_TX_TIMEOUT);
00709   LPM_Mode_Request(eLPM_SPI_TX, eLPM_Mode_LP_Stop);
00710   
00711   return;
00712 }
00713 #endif /* ENABLE_SPI_FIX */
00714 
00715 /**
00716  * @brief  Tx and Rx Transfer completed callbacks
00717  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
00718  *               the configuration information for SPI module.
00719  * @retval None
00720  */
00721 void BlueNRG_DMA_TxCallback(void)
00722 {
00723   __HAL_DMA_CLEAR_FLAG(SPI_Context.hspi->hdmatx, BNRG_SPI_TX_DMA_TC_FLAG);
00724   
00725   switch (SPI_Context.SPI_Transmit_Context.Spi_Transmit_Event)
00726   {
00727   case SPI_HEADER_TRANSMITTED:
00728     if(SPI_Context.SPI_Transmit_Context.payload_size_to_transmit != 0)
00729     {
00730       SPI_Transmit_Manager(SPI_PAYLOAD_TRANSMIT);
00731     }
00732     else
00733     {
00734       TransmitClosure();
00735     }
00736     break;
00737     
00738   case SPI_PAYLOAD_TRANSMITTED:
00739     if( (SPI_Context.SPI_Transmit_Context.packet_cont == TRUE) && (SPI_Context.SPI_Transmit_Context.payload_size != 0))
00740     {
00741       SPI_Context.SPI_Transmit_Context.payload_data += SPI_Context.SPI_Transmit_Context.payload_size_to_transmit;
00742       DisableEnable_SPI_CS();
00743       SPI_Receive_Manager(SPI_REQUEST_VALID_HEADER_FOR_TX);
00744     }
00745     else
00746     {
00747       TransmitClosure();
00748     }
00749     break;
00750     
00751   default:
00752     break;
00753   }
00754   
00755   return;
00756 }
00757 
00758 /**
00759  * @brief  Close the transmit mechanism after packet has been sent
00760  *         Wait for the event to come back
00761  * @param  None
00762  * @retval None
00763  */
00764 static void TransmitClosure(void)
00765 { 
00766   LPM_Mode_Request(eLPM_SPI_TX, eLPM_Mode_LP_Stop);
00767   SPI_Context.Spi_Peripheral_State = SPI_AVAILABLE;
00768   Disable_SPI_CS();
00769   /*
00770    *  Disable both DMA
00771    */
00772   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmatx);
00773   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmarx);
00774   Enable_SPI_Receiving_Path();
00775   
00776   return;
00777 }
00778 
00779 /**
00780  * @brief  Manage the SPI transmit
00781  * @param  TransmitRequest: the transmit request
00782  * @retval None
00783  */
00784 static void SPI_Transmit_Manager(SPI_TRANSMIT_REQUEST_t TransmitRequest)
00785 {
00786   /*
00787    *  Disable both DMA
00788    */
00789   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmatx);
00790   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmarx);
00791   
00792   __HAL_DMA_DISABLE_IT(SPI_Context.hspi->hdmarx, DMA_IT_TC); /**< Disable Receive packet notification */
00793   
00794   __HAL_DMA_CLEAR_FLAG(SPI_Context.hspi->hdmatx, BNRG_SPI_TX_DMA_TC_FLAG); /**< Clear flag in DMA */
00795     HAL_NVIC_ClearPendingIRQ(BNRG_SPI_DMA_TX_IRQn); /**< Clear DMA pending bit in NVIC */
00796   __HAL_DMA_ENABLE_IT(SPI_Context.hspi->hdmatx, DMA_IT_TC); /**< Enable Transmit packet notification */
00797   
00798   __HAL_BLUENRG_DMA_SET_MINC(SPI_Context.hspi->hdmatx); /**< Configure DMA to send Tx packet */
00799   
00800   switch (TransmitRequest)
00801   {
00802   case SPI_HEADER_TRANSMIT:
00803     SPI_Context.SPI_Transmit_Context.Spi_Transmit_Event = SPI_HEADER_TRANSMITTED;
00804     
00805 #ifdef ENABLE_SPI_FIX
00806     set_irq_as_input();
00807 #endif
00808     
00809     __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmatx, SPI_Context.SPI_Transmit_Context.header_size); /**< Set counter in DMA TX */
00810     __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmatx, (uint32_t)SPI_Context.SPI_Transmit_Context.header_data); /**< Set memory address in DMA TX */
00811     break;
00812     
00813   case SPI_PAYLOAD_TRANSMIT:
00814     SPI_Context.SPI_Transmit_Context.Spi_Transmit_Event = SPI_PAYLOAD_TRANSMITTED;
00815     
00816     __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmatx, SPI_Context.SPI_Transmit_Context.payload_size_to_transmit); /**< Set counter in DMA TX */
00817     __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmatx, (uint32_t)SPI_Context.SPI_Transmit_Context.payload_data); /**< Set memory address in DMA TX */
00818     break;
00819     
00820   default:
00821     break;
00822   }
00823   
00824   __HAL_DMA_ENABLE(SPI_Context.hspi->hdmatx); /**< Enable DMA TX */
00825   
00826 }
00827 
00828 /**
00829  * @brief  Manage the SPI receive
00830  * @param  ReceiveRequest: the receive request
00831  * @retval None
00832  */
00833 static void SPI_Receive_Manager(SPI_RECEIVE_REQUEST_t ReceiveRequest)
00834 {
00835   uint16_t byte_count;
00836     uint8_t localloop;
00837   
00838   /*
00839    *  Disable both DMA
00840    */
00841   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmatx);
00842   __HAL_DMA_DISABLE(SPI_Context.hspi->hdmarx);
00843   
00844   /**
00845    * Flush the Rx register or FIFO
00846    */
00847   for (localloop = 0 ; localloop < SPI_FIFO_RX_DEPTH ; localloop++)
00848   {
00849     *(volatile uint8_t*)__HAL_BLUENRG_SPI_GET_RX_DATA_REGISTER_ADDRESS(SPI_Context.hspi);
00850   }
00851   
00852   __HAL_DMA_ENABLE_IT(SPI_Context.hspi->hdmarx, DMA_IT_TC); /**< Enable Receive packet notification */
00853   __HAL_DMA_DISABLE_IT(SPI_Context.hspi->hdmatx, DMA_IT_TC); /**< Disable Transmit packet notification */
00854   
00855   switch (ReceiveRequest)
00856   {
00857   case SPI_REQUEST_VALID_HEADER_FOR_RX:
00858     ReceiveHeader(SPI_CHECK_RECEIVED_HEADER_FOR_RX, (uint8_t *)Read_Header_CMD);
00859     break;
00860     
00861   case SPI_REQUEST_VALID_HEADER_FOR_TX:
00862     ReceiveHeader(SPI_CHECK_RECEIVED_HEADER_FOR_TX, (uint8_t *)Write_Header_CMD);
00863     break;
00864     
00865   case SPI_REQUEST_PAYLOAD:
00866     SPI_Context.SPI_Receive_Context.Spi_Receive_Event = SPI_RECEIVE_END;
00867     
00868     /*
00869      * Check data to received is not available buffer size
00870      */
00871     byte_count = (Received_Header[4]<<8)|Received_Header[3];
00872     if (byte_count > SPI_Context.SPI_Receive_Context.buffer_size)
00873     {
00874       byte_count = SPI_Context.SPI_Receive_Context.buffer_size;
00875     }
00876     SPI_Context.SPI_Receive_Context.payload_len = byte_count;
00877     
00878     __HAL_BLUENRG_DMA_CLEAR_MINC(SPI_Context.hspi->hdmatx); /**< Configure DMA to send same Byte */
00879     
00880     /*
00881      *  Set counter in both DMA
00882      */
00883     __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmarx, byte_count);
00884     __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmatx, byte_count);
00885     
00886     /*
00887      *  Set memory address in both DMA
00888      */
00889     __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmarx, (uint32_t)SPI_Context.SPI_Receive_Context.buffer);
00890     __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmatx, (uint32_t)&dummy_bytes);
00891     break;
00892     
00893   default:
00894     break;
00895   }
00896   
00897   /*
00898    *  Enable both DMA - Rx First
00899    */
00900   __HAL_DMA_ENABLE(SPI_Context.hspi->hdmarx);
00901   __HAL_DMA_ENABLE(SPI_Context.hspi->hdmatx);
00902   
00903   return;
00904 }
00905 
00906 /**
00907  * @brief Receive header
00908  * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
00909  *               the configuration information for SPI module.
00910  * @retval None
00911  */
00912 static void ReceiveHeader(SPI_RECEIVE_EVENT_t ReceiveEvent, uint8_t * DataHeader)
00913 {
00914   SPI_Context.SPI_Receive_Context.Spi_Receive_Event = ReceiveEvent;
00915   
00916   __HAL_BLUENRG_DMA_SET_MINC(SPI_Context.hspi->hdmatx); /**< Configure DMA to send Tx packet */
00917   
00918   /*
00919    *  Set counter in both DMA
00920    */
00921   __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmatx, HEADER_SIZE);
00922   __HAL_BLUENRG_DMA_SET_COUNTER(SPI_Context.hspi->hdmarx, HEADER_SIZE);
00923   
00924   /*
00925    *  Set memory address in both DMA
00926    */
00927   __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmarx, (uint32_t)Received_Header);
00928   __HAL_BLUENRG_DMA_SET_MEMORY_ADDRESS(SPI_Context.hspi->hdmatx, (uint32_t)DataHeader);
00929   
00930   return;
00931 }
00932 
00933 /**
00934  * @brief  BlueNRG SPI request event
00935  * @param  buffer: the event
00936  * @param  buff_size: the event size
00937  * @retval None
00938  */
00939 void BlueNRG_SPI_Request_Events(uint8_t *buffer, uint8_t buff_size)
00940 {
00941   SPI_Context.SPI_Receive_Context.buffer = buffer;
00942   SPI_Context.SPI_Receive_Context.buffer_size = buff_size;
00943   
00944   Enable_SPI_Receiving_Path();
00945   
00946   return;
00947 }
00948 
00949 /**
00950  * @brief  BlueNRG SPI IRQ Callback
00951  * @param  None
00952  * @retval None
00953  */
00954 void BlueNRG_SPI_IRQ_Callback(void)
00955 {  
00956   __disable_irq();
00957   if(SPI_Context.Spi_Peripheral_State == SPI_AVAILABLE)
00958   {
00959     SPI_Context.Spi_Peripheral_State = SPI_BUSY;
00960     __enable_irq();
00961     Enable_SPI_CS();
00962     SPI_Receive_Manager(SPI_REQUEST_VALID_HEADER_FOR_RX);
00963     LPM_Mode_Request(eLPM_SPI_RX, eLPM_Mode_Sleep);
00964   }
00965   else
00966   {
00967     __enable_irq();
00968   }
00969 }
00970 
00971 #endif /* __DMA_LP__ */
00972 
00973 /**
00974  * @}
00975  */
00976 
00977 /**
00978  * @}
00979  */
00980  
00981 /**
00982  * @}
00983  */
00984 
00985 /**
00986  * @}
00987  */
00988 
00989 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/