Filippo Casamassima / Nucleo_blueNRG

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers stm32_bluenrg_ble.c Source File

stm32_bluenrg_ble.c

Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32_bluenrg_ble.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 /* Includes ------------------------------------------------------------------*/
00039 #include "stm32_bluenrg_ble.h "
00040 #include "gp_timer.h"
00041 #include "debug.h"
00042 
00043 #define HEADER_SIZE 5
00044 #define MAX_BUFFER_SIZE 255
00045 #define TIMEOUT_DURATION 15
00046 
00047 SPI_HandleTypeDef SpiHandle;
00048 
00049 /* Private function prototypes -----------------------------------------------*/
00050 static void us150Delay(void);
00051 void set_irq_as_output(void);
00052 void set_irq_as_input(void);
00053 
00054 /**
00055  * @brief  This function is used for low level initialization of the SPI 
00056  *         communication with the BlueNRG Expansion Board.
00057  * @param  Pointer to the handle of the STM32Cube HAL SPI interface.
00058  * @retval None
00059  */
00060 void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
00061 {
00062   GPIO_InitTypeDef GPIO_InitStruct;
00063   if(hspi->Instance==BNRG_SPI_INSTANCE)
00064   {
00065     /* Enable peripherals clock */
00066     
00067     /* Enable GPIO Ports Clock */  
00068     BNRG_SPI_RESET_CLK_ENABLE();
00069     BNRG_SPI_SCLK_CLK_ENABLE();
00070     BNRG_SPI_MISO_CLK_ENABLE();
00071     BNRG_SPI_MOSI_CLK_ENABLE();
00072     BNRG_SPI_CS_CLK_ENABLE();
00073     BNRG_SPI_IRQ_CLK_ENABLE();
00074     
00075     /* Enable SPI clock */
00076     BNRG_SPI_CLK_ENABLE();
00077     
00078     /* Reset */
00079     GPIO_InitStruct.Pin = BNRG_SPI_RESET_PIN;
00080     GPIO_InitStruct.Mode = BNRG_SPI_RESET_MODE;
00081     GPIO_InitStruct.Pull = BNRG_SPI_RESET_PULL;
00082     GPIO_InitStruct.Speed = BNRG_SPI_RESET_SPEED;
00083     GPIO_InitStruct.Alternate = BNRG_SPI_RESET_ALTERNATE;
00084     HAL_GPIO_Init(BNRG_SPI_RESET_PORT, &GPIO_InitStruct);   
00085     HAL_GPIO_WritePin(BNRG_SPI_RESET_PORT, BNRG_SPI_RESET_PIN, GPIO_PIN_RESET); /*Added to avoid spurious interrupt from the BlueNRG */
00086     
00087     /* SCLK */
00088     GPIO_InitStruct.Pin = BNRG_SPI_SCLK_PIN;
00089     GPIO_InitStruct.Mode = BNRG_SPI_SCLK_MODE;
00090     GPIO_InitStruct.Pull = BNRG_SPI_SCLK_PULL;
00091     GPIO_InitStruct.Speed = BNRG_SPI_SCLK_SPEED;
00092     GPIO_InitStruct.Alternate = BNRG_SPI_SCLK_ALTERNATE;
00093     HAL_GPIO_Init(BNRG_SPI_SCLK_PORT, &GPIO_InitStruct); 
00094     
00095     /* MISO */
00096     GPIO_InitStruct.Pin = BNRG_SPI_MISO_PIN;
00097     GPIO_InitStruct.Mode = BNRG_SPI_MISO_MODE;
00098     GPIO_InitStruct.Pull = BNRG_SPI_MISO_PULL;
00099     GPIO_InitStruct.Speed = BNRG_SPI_MISO_SPEED;
00100     GPIO_InitStruct.Alternate = BNRG_SPI_MISO_ALTERNATE;
00101     HAL_GPIO_Init(BNRG_SPI_MISO_PORT, &GPIO_InitStruct);
00102     
00103     /* MOSI */
00104     GPIO_InitStruct.Pin = BNRG_SPI_MOSI_PIN;
00105     GPIO_InitStruct.Mode = BNRG_SPI_MOSI_MODE;
00106     GPIO_InitStruct.Pull = BNRG_SPI_MOSI_PULL;
00107     GPIO_InitStruct.Speed = BNRG_SPI_MOSI_SPEED;
00108     GPIO_InitStruct.Alternate = BNRG_SPI_MOSI_ALTERNATE;
00109     HAL_GPIO_Init(BNRG_SPI_MOSI_PORT, &GPIO_InitStruct);
00110     
00111     /* NSS/CSN/CS */
00112     GPIO_InitStruct.Pin = BNRG_SPI_CS_PIN;
00113     GPIO_InitStruct.Mode = BNRG_SPI_CS_MODE;
00114     GPIO_InitStruct.Pull = BNRG_SPI_CS_PULL;
00115     GPIO_InitStruct.Speed = BNRG_SPI_CS_SPEED;
00116     GPIO_InitStruct.Alternate = BNRG_SPI_CS_ALTERNATE;
00117     HAL_GPIO_Init(BNRG_SPI_CS_PORT, &GPIO_InitStruct);
00118     HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET);
00119     
00120     /* IRQ -- INPUT */
00121     GPIO_InitStruct.Pin = BNRG_SPI_IRQ_PIN;
00122     GPIO_InitStruct.Mode = BNRG_SPI_IRQ_MODE;
00123     GPIO_InitStruct.Pull = BNRG_SPI_IRQ_PULL;
00124     GPIO_InitStruct.Speed = BNRG_SPI_IRQ_SPEED;
00125     GPIO_InitStruct.Alternate = BNRG_SPI_IRQ_ALTERNATE;
00126     HAL_GPIO_Init(BNRG_SPI_IRQ_PORT, &GPIO_InitStruct);
00127     
00128     /* Configure the NVIC for SPI */  
00129     HAL_NVIC_SetPriority(BNRG_SPI_EXTI_IRQn, 4, 0);    
00130     HAL_NVIC_EnableIRQ(BNRG_SPI_EXTI_IRQn);
00131   }
00132 }
00133 
00134 /**
00135  * @brief  Writes data to a serial interface.
00136  * @param  data1   :  1st buffer
00137  * @param  data2   :  2nd buffer
00138  * @param  n_bytes1: number of bytes in 1st buffer
00139  * @param  n_bytes2: number of bytes in 2nd buffer
00140  * @retval None
00141  */
00142 void Hal_Write_Serial(const void* data1, const void* data2, int32_t n_bytes1,
00143                       int32_t n_bytes2)
00144 {
00145   struct timer t;
00146   
00147   Timer_Set(&t, CLOCK_SECOND/10);
00148   
00149 #ifdef PRINT_CSV_FORMAT
00150   PRINT_CSV("00:00:00.000");
00151   for (int i=0; i<n_bytes1; i++) {
00152     PRINT_CSV(" %02x", ((uint8_t *)data1)[i]);
00153   }
00154   for (int i=0; i<n_bytes2; i++) {
00155     PRINT_CSV(" %02x", ((uint8_t *)data2)[i]);
00156   }
00157   PRINT_CSV("\n");
00158 #endif
00159 
00160   while(1){
00161     if(BlueNRG_SPI_Write(&SpiHandle, (uint8_t *)data1,(uint8_t *)data2, n_bytes1, n_bytes2)==0) break;
00162     if(Timer_Expired(&t)){
00163       break;
00164     }
00165   }
00166 }
00167 
00168 /**
00169 * @brief  Initializes the SPI communication with the BlueNRG
00170 *         Expansion Board.
00171 * @param  None
00172 * @retval None
00173 */
00174 void BNRG_SPI_Init(void)
00175 {
00176   SpiHandle.Instance = BNRG_SPI_INSTANCE;
00177   SpiHandle.Init.Mode = BNRG_SPI_MODE;
00178   SpiHandle.Init.Direction = BNRG_SPI_DIRECTION;
00179   SpiHandle.Init.DataSize = BNRG_SPI_DATASIZE;
00180   SpiHandle.Init.CLKPolarity = BNRG_SPI_CLKPOLARITY;
00181   SpiHandle.Init.CLKPhase = BNRG_SPI_CLKPHASE;
00182   SpiHandle.Init.NSS = BNRG_SPI_NSS;
00183   SpiHandle.Init.FirstBit = BNRG_SPI_FIRSTBIT;
00184   SpiHandle.Init.TIMode = BNRG_SPI_TIMODE;
00185   SpiHandle.Init.CRCPolynomial = BNRG_SPI_CRCPOLYNOMIAL;
00186   SpiHandle.Init.BaudRatePrescaler = BNRG_SPI_BAUDRATEPRESCALER;
00187   SpiHandle.Init.CRCCalculation = BNRG_SPI_CRCCALCULATION;
00188   
00189   HAL_SPI_Init(&SpiHandle);
00190 }
00191 
00192 /**
00193  * @brief  Resets the BlueNRG.
00194  * @param  None
00195  * @retval None
00196  */
00197 void BlueNRG_RST(void)
00198 {    
00199   HAL_GPIO_WritePin(BNRG_SPI_RESET_PORT, BNRG_SPI_RESET_PIN, GPIO_PIN_RESET);
00200   HAL_Delay(5);
00201   HAL_GPIO_WritePin(BNRG_SPI_RESET_PORT, BNRG_SPI_RESET_PIN, GPIO_PIN_SET);
00202   HAL_Delay(5);
00203 }
00204 
00205 
00206 /**
00207   * @brief  Reports if the BlueNRG has data for the host micro.
00208   * @param  None
00209   * @retval 1 if data are present, 0 otherwise
00210   */
00211 // FIXME: find a better way to handle this return value (bool type? TRUE and FALSE)
00212 uint8_t BlueNRG_DataPresent(void)
00213 {
00214   if (HAL_GPIO_ReadPin(BNRG_SPI_EXTI_PORT, BNRG_SPI_EXTI_PIN) == GPIO_PIN_SET)
00215       return 1;
00216   else  
00217       return 0;
00218 } /* end BlueNRG_DataPresent() */
00219 
00220 /**
00221   * @brief  Activate internal bootloader using pin.
00222   * @param  None
00223   * @retval None
00224   */
00225 void BlueNRG_HW_Bootloader(void)
00226 {
00227   set_irq_as_output();
00228   BlueNRG_RST();
00229   set_irq_as_input();
00230 }
00231 
00232 /**
00233 * @brief  Reads from BlueNRG SPI buffer and store data into local buffer.
00234 * @param  hspi     : Handle of the STM32Cube HAL SPI interface
00235 * @param  buffer   : Buffer where data from SPI are stored
00236 * @param  buff_size: Buffer size
00237 * @retval int32_t  : Number of read bytes
00238 */
00239 int32_t BlueNRG_SPI_Read_All(SPI_HandleTypeDef *hspi, uint8_t *buffer,
00240                              uint8_t buff_size)
00241 {
00242   uint16_t byte_count;
00243   uint8_t len = 0;
00244   uint8_t char_ff = 0xff;
00245   volatile uint8_t read_char;
00246   
00247   uint8_t header_master[HEADER_SIZE] = {0x0b, 0x00, 0x00, 0x00, 0x00};
00248   uint8_t header_slave[HEADER_SIZE];
00249       
00250   /* CS reset */
00251   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_RESET);
00252 
00253   /* Read the header */  
00254   HAL_SPI_TransmitReceive(hspi, header_master, header_slave, HEADER_SIZE, TIMEOUT_DURATION);
00255    
00256   if (header_slave[0] == 0x02) {
00257     /* device is ready */
00258     byte_count = (header_slave[4]<<8)|header_slave[3];
00259     
00260     if (byte_count > 0) {
00261       
00262       /* avoid to read more data that size of the buffer */
00263       if (byte_count > buff_size){
00264         byte_count = buff_size;
00265       }
00266       
00267       for (len = 0; len < byte_count; len++){
00268         HAL_SPI_TransmitReceive(hspi, &char_ff, (uint8_t*)&read_char, 1, TIMEOUT_DURATION);
00269         buffer[len] = read_char;
00270       }
00271     }    
00272   }
00273   /* Release CS line */
00274   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET);
00275   
00276   // Add a small delay to give time to the BlueNRG to set the IRQ pin low
00277   // to avoid a useless SPI read at the end of the transaction
00278   for(volatile int i = 0; i < 2; i++)__NOP();
00279 
00280 #ifdef PRINT_CSV_FORMAT
00281   if (len > 0) {
00282     PRINT_CSV("00:00:00.000");
00283     for (int i=0; i<len; i++) {
00284       PRINT_CSV(" %02x", buffer[i]);
00285     }
00286     PRINT_CSV("\n");
00287   }
00288 #endif
00289 
00290   return len;   
00291 }
00292 
00293 /**
00294 * @brief  Writes data from local buffer to SPI.
00295 * @param  hspi     : Handle of the STM32Cube HAL SPI interface
00296 * @param  data1    : First data buffer to be written
00297 * @param  data2    : Second data buffer to be written
00298 * @param  Nb_bytes1: Size of first data buffer to be written
00299 * @param  Nb_bytes2: Size of second data buffer to be written
00300 * @retval Number of read bytes
00301 */
00302 int32_t BlueNRG_SPI_Write(SPI_HandleTypeDef *hspi, uint8_t* data1,
00303                           uint8_t* data2, uint8_t Nb_bytes1, uint8_t Nb_bytes2)
00304 {  
00305   int32_t result = 0;
00306   
00307   int32_t spi_fix_enabled = 0;
00308   
00309 #ifdef ENABLE_SPI_FIX
00310   spi_fix_enabled = 1;
00311 #endif //ENABLE_SPI_FIX
00312   
00313   unsigned char header_master[HEADER_SIZE] = {0x0a, 0x00, 0x00, 0x00, 0x00};
00314   unsigned char header_slave[HEADER_SIZE]  = {0xaa, 0x00, 0x00, 0x00, 0x00};
00315   
00316   unsigned char read_char_buf[MAX_BUFFER_SIZE];
00317   
00318   Disable_SPI_IRQ(); 
00319   
00320   /*
00321    If the SPI_FIX is enabled the IRQ is set in Output mode, then it is pulled
00322    high and, after a delay of at least 112us, the CS line is asserted and the
00323    header transmit/receive operations are started.
00324    After these transmit/receive operations the IRQ is reset in input mode.
00325   */
00326   if (spi_fix_enabled) {
00327     set_irq_as_output();
00328     
00329     /* Assert CS line after at least 112us */
00330     us150Delay();
00331   }
00332   
00333   /* CS reset */
00334   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_RESET);
00335   
00336   /* Exchange header */  
00337   HAL_SPI_TransmitReceive(hspi, header_master, header_slave, HEADER_SIZE, TIMEOUT_DURATION);
00338   
00339   if (spi_fix_enabled) {
00340     set_irq_as_input();
00341   }
00342   
00343   if (header_slave[0] == 0x02) {
00344     /* SPI is ready */
00345     if (header_slave[1] >= (Nb_bytes1+Nb_bytes2)) {
00346       
00347       /*  Buffer is big enough */
00348       if (Nb_bytes1 > 0) {
00349         HAL_SPI_TransmitReceive(hspi, data1, read_char_buf, Nb_bytes1, TIMEOUT_DURATION);
00350       }
00351       if (Nb_bytes2 > 0) {
00352         HAL_SPI_TransmitReceive(hspi, data2, read_char_buf, Nb_bytes2, TIMEOUT_DURATION);
00353       }
00354             
00355     } else {
00356       /* Buffer is too small */
00357       result = -2;
00358     }
00359   } else {
00360     /* SPI is not ready */
00361     result = -1;
00362   }
00363   
00364   /* Release CS line */
00365   HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET);
00366   
00367   Enable_SPI_IRQ();
00368   
00369   return result;
00370 }
00371 
00372 /**
00373  * @brief  Set in Output mode the IRQ.
00374  * @param  None
00375  * @retval None
00376  */
00377 void set_irq_as_output()
00378 {
00379   GPIO_InitTypeDef  GPIO_InitStructure;
00380   
00381   /* Pull IRQ high */
00382   GPIO_InitStructure.Pin = BNRG_SPI_IRQ_PIN;
00383   GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
00384   GPIO_InitStructure.Speed = BNRG_SPI_IRQ_SPEED;
00385   GPIO_InitStructure.Pull = GPIO_NOPULL;
00386   HAL_GPIO_Init(BNRG_SPI_IRQ_PORT, &GPIO_InitStructure);
00387   HAL_GPIO_WritePin(BNRG_SPI_IRQ_PORT, BNRG_SPI_IRQ_PIN, GPIO_PIN_SET);
00388 }
00389 
00390 /**
00391  * @brief  Set the IRQ in input mode.
00392  * @param  None
00393  * @retval None
00394  */
00395 void set_irq_as_input()
00396 {
00397   GPIO_InitTypeDef  GPIO_InitStructure;
00398   
00399   /* IRQ input */  
00400   GPIO_InitStructure.Pin = BNRG_SPI_IRQ_PIN;
00401   GPIO_InitStructure.Mode = BNRG_SPI_IRQ_MODE;
00402   GPIO_InitStructure.Pull = GPIO_PULLDOWN;
00403   GPIO_InitStructure.Speed = BNRG_SPI_IRQ_SPEED;
00404   GPIO_InitStructure.Alternate = BNRG_SPI_IRQ_ALTERNATE;    
00405   HAL_GPIO_Init(BNRG_SPI_IRQ_PORT, &GPIO_InitStructure);
00406   
00407   GPIO_InitStructure.Pull = BNRG_SPI_IRQ_PULL;
00408   HAL_GPIO_Init(BNRG_SPI_IRQ_PORT, &GPIO_InitStructure);
00409 }
00410 
00411 /**
00412   * @brief  Utility function for delay
00413   * @param  None 
00414   * @retval None
00415   * NOTE: TODO: implement with clock-independent function.
00416   */
00417 static void us150Delay()
00418 { 
00419 #if SYSCLK_FREQ == 4000000
00420   for(volatile int i = 0; i < 35; i++)__NOP();
00421 #elif SYSCLK_FREQ == 32000000
00422   for(volatile int i = 0; i < 420; i++)__NOP();
00423 #elif SYSCLK_FREQ == 84000000
00424   for(volatile int i = 0; i < 1125; i++)__NOP();
00425 #else
00426 #error Implement delay function.
00427 #endif    
00428 }
00429 
00430 /**
00431  * @brief  Enable SPI IRQ.
00432  * @param  None
00433  * @retval None
00434  */
00435 void Enable_SPI_IRQ(void)
00436 {  
00437   HAL_NVIC_EnableIRQ(BNRG_SPI_EXTI_IRQn);  
00438 }
00439 
00440 /**
00441  * @brief  Disable SPI IRQ.
00442  * @param  None
00443  * @retval None
00444  */
00445 void Disable_SPI_IRQ(void)
00446 {  
00447   HAL_NVIC_DisableIRQ(BNRG_SPI_EXTI_IRQn);
00448 }
00449 
00450 /**
00451  * @brief  Clear Pending SPI IRQ.
00452  * @param  None
00453  * @retval None
00454  */
00455 void Clear_SPI_IRQ(void)
00456 {
00457   HAL_NVIC_ClearPendingIRQ(BNRG_SPI_EXTI_IRQn);
00458 }
00459 
00460 /**
00461  * @brief  Clear EXTI (External Interrupt) line for SPI IRQ.
00462  * @param  None
00463  * @retval None
00464  */
00465 void Clear_SPI_EXTI_Flag(void)
00466 {
00467   __HAL_GPIO_EXTI_CLEAR_IT(BNRG_SPI_EXTI_PIN);
00468 }
00469     
00470 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
00471