Fahad Mirza
/
Nucleo_HXC900
A demo application for HXC900 LoRaWAN module using Nucleo-L053R8.
Driver/hw_usart.c
- Committer:
- fahadmirza
- Date:
- 2019-01-24
- Revision:
- 39:cb0e5a76ab15
- Parent:
- 5:53302861bfea
File content as of revision 39:cb0e5a76ab15:
/****************************************************************************** * File : hw_usart.c * Author : Fahad Mirza (Haxiot) * Date : 08-January-2018 * Brief : Configuration of the USART instances. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2017 Haxiot. All rights reserved.</center></h2> * * Redistribution and use in source and binary forms, with or without * modification, are permitted, provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of other * contributors to this software may be used to endorse or promote products * derived from this software without specific written permission. * 4. Redistribution and use of this software other than as permitted under * this license is void and will automatically terminate your rights under * this license. * * THIS SOFTWARE IS PROVIDED BY HAXIOT AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /*---- Includes ----------------------------------------------*/ #include "hw.h" #include "low_power_manager.h" #include "time_server.h" /*---- Private variable --------------------------------------------------------*/ static struct { char buffTx[256]; /* structure have to be simplified*/ char buffRx[256]; int rx_idx_free; int rx_idx_toread; HW_LockTypeDef Lock; __IO HAL_UART_StateTypeDef gState; __IO HAL_UART_StateTypeDef RxState; } uart_context; /*---- private function --------------------------------------------------------*/ static void receive(char rx); /*---- private Global variables ------------------------------------------------*/ static UART_HandleTypeDef hxcUart; /*---- Function Definitions ----------------------------------------------------*/ bool HW_UART_Modem_Init(uint32_t BaudRate) { hxcUart.Instance = HXC_USARTX; hxcUart.Init.BaudRate = BaudRate; hxcUart.Init.WordLength = UART_WORDLENGTH_8B; hxcUart.Init.StopBits = UART_STOPBITS_1; hxcUart.Init.Parity = UART_PARITY_NONE; hxcUart.Init.Mode = UART_MODE_TX_RX; hxcUart.Init.HwFlowCtl = UART_HWCONTROL_NONE; hxcUart.Init.OverSampling = UART_OVERSAMPLING_16; hxcUart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; hxcUart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; hxcUart.gState = HAL_UART_STATE_RESET; if(HAL_UART_Init(&hxcUart) != HAL_OK) { // Initialization Error return false; } /* Computation of UART mask to apply to RDR register */ UART_MASK_COMPUTATION(&hxcUart); /*******************************************************************/ /*see Application Note AN4991 : how to wake up an STM32L0 MCU from */ /*low power mode with the USART or the LPUART */ /*******************************************************************/ /* Enable the UART Parity Error and Data Register not empty Interrupts */ SET_BIT(hxcUart.Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ SET_BIT(hxcUart.Instance->CR3, USART_CR3_EIE); /*Enable UART Stop Mode*/ HAL_UARTEx_EnableStopMode(&hxcUart); // Enable wakeup from stop mode active on start bit detection MODIFY_REG(hxcUart.Instance->CR3, USART_CR3_WUS, USART_CR3_WUS_1); // Enable Wake Up from Stop Mode Interrupt SET_BIT(hxcUart.Instance->CR3, USART_CR3_WUFIE); hxcUart.ErrorCode = HAL_UART_ERROR_NONE; hxcUart.RxState = HAL_UART_STATE_READY; return true; } void HAL_UART_MspInit(UART_HandleTypeDef* huart) { GPIO_InitTypeDef GPIO_InitStruct; /***************************************************************/ /* GPIO Configuration for UART2 or for LPUART1 */ /* for USART1 use: */ /* PA10 ------> USART1_RX */ /* PA9 ------> USART1_TX */ /* else for USART2 use: */ /* PA2 ------> USART2_TX */ /* PA3 ------> USART2_RX */ /***************************************************************/ /* We need both instances. One UART is used for HXC and * another one is used for debug printf. As HAL_UART_Init() * uses HAL_UART_MspInit(), we needed to cover both instances. */ if(huart->Instance == USART1) { // Peripheral clock enable __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = GPIO_AF4_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } else if(huart->Instance == USART2) { // Peripheral clock enable __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = GPIO_AF4_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } if(huart->Instance == HXC_USARTX) { // Peripheral interrupt init HAL_NVIC_SetPriority(HXC_USARTX_IRQn, 0, 0); HAL_NVIC_EnableIRQ(HXC_USARTX_IRQn); } } void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) { if(huart->Instance == USART1) { /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); } else if(huart->Instance == USART2) { /* Peripheral clock disable */ __HAL_RCC_USART2_CLK_DISABLE(); HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); } if(huart->Instance == HXC_USARTX) { /* Peripheral interrupt Deinit*/ HAL_NVIC_DisableIRQ(HXC_USARTX_IRQn); } } void HW_UART_Modem_DeInit(void) { HAL_UART_DeInit(&hxcUart); } bool HW_UART_Modem_Receive_IT (uint8_t *aRxBuffer) { return ( HAL_UART_Receive_IT(&hxcUart, aRxBuffer, 1) == HAL_OK ); } /****************************************************************************** * @brief Handler on Rx IRQ * @param handle to the UART * @retval void ******************************************************************************/ void HW_UART_Modem_IRQHandler(void) { UART_HandleTypeDef *huart = &hxcUart; //ToDo uint32_t isrflags = READ_REG(huart->Instance->ISR); uint32_t cr1its = READ_REG(huart->Instance->CR1); uint32_t cr3its = READ_REG(huart->Instance->CR3);; uint32_t errorflags; char rxByte = '\0'; int rx_ready = 0; huart->RxState = HAL_UART_STATE_BUSY_RX; /* UART wakeup from Stop mode interrupt occurred ---------------------------*/ if(((isrflags & USART_ISR_WUF) != RESET) && ((cr3its & USART_CR3_WUFIE) != RESET)) { __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF); /* forbid stop mode */ LPM_SetStopMode(LPM_UART_RX_Id , LPM_Disable ); /* Enable the UART Data Register not empty Interrupts */ SET_BIT(huart->Instance->CR1, USART_CR1_RXNEIE); /* Set the UART state ready to be able to start again the process */ huart->gState = HAL_UART_STATE_READY; huart->RxState = HAL_UART_STATE_READY; } /* UART in mode Receiver ---------------------------------------------------*/ if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) { /* Check that a Rx process is ongoing */ if(huart->RxState == HAL_UART_STATE_BUSY_RX) { /*RXNE flag is auto cleared by reading the data*/ rxByte = (uint8_t)READ_REG(huart->Instance->RDR); /* allow stop mode*/ LPM_SetStopMode(LPM_UART_RX_Id , LPM_Enable ); huart->RxState = HAL_UART_STATE_READY; rx_ready = 1; /* not used RxTC callback*/ } else { // Clear RXNE interrupt flag __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST); return; } } // If error occurs errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE)); if (errorflags != RESET) { // Error on receiving __HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF); __HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF); __HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF); __HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF); // we skip the overrun case rx_ready = 1; } if(rx_ready) { // Put received character in the ring buffer receive(rxByte); } } /****************************************************************************** * @Brief : Read a complete string until <CR><LF> * @Param : rxBuffer - pointer for received characters * rxBufferSize - size of the rxBuffer * @Retval: Return the number of characters received ******************************************************************************/ uint8_t HW_UART_Modem_GetCharactersUntilNewLine(char *rxBuffer, uint8_t rxBufferSize, uint32_t timeout) { uint8_t len = 0; uint32_t currentTime = TimerGetCurrentTime(); while(len < (rxBufferSize - 1)) // Keep 1 byte for NULL { if(HW_UART_Modem_IsNewCharReceived() == false) { if(TimerGetElapsedTime(currentTime) > timeout) { break; } } else { rxBuffer[len++] = (char)HW_UART_Modem_GetNewChar(); if(rxBuffer[len - 1] == '\n') { break; } } } rxBuffer[len] = '\0'; return len; } /****************************************************************************** * @brief To check if data has been received * @param none * @retval false no data / true data ******************************************************************************/ bool HW_UART_Modem_IsNewCharReceived(void) { bool status; // ToDo : why STM used separate PRIMASK()? //BACKUP_PRIMASK(); uint32_t primask_bit= __get_PRIMASK(); //DISABLE_IRQ(); __disable_irq(); status = ((uart_context.rx_idx_toread == uart_context.rx_idx_free) ? false : true); //RESTORE_PRIMASK(); __set_PRIMASK(primask_bit); return status; } /****************************************************************************** * @brief Get the received character * @param none * @retval Return the data received ******************************************************************************/ uint8_t HW_UART_Modem_GetNewChar(void) { uint8_t NewChar; // BACKUP_PRIMASK(); uint32_t primask_bit= __get_PRIMASK(); // DISABLE_IRQ(); __disable_irq(); NewChar = uart_context.buffRx[uart_context.rx_idx_toread]; uart_context.rx_idx_toread = (uart_context.rx_idx_toread + 1) % sizeof(uart_context.buffRx); // RESTORE_PRIMASK(); __set_PRIMASK(primask_bit); return NewChar; } /****************************************************************************** * @brief Reset read and write index of the circular buffer * @param none * @retval none ******************************************************************************/ void HW_UART_ResetBuffer(void) { BACKUP_PRIMASK(); DISABLE_IRQ(); uart_context.rx_idx_toread = uart_context.rx_idx_free; RESTORE_PRIMASK(); } /****************************************************************************** * @Brief : Send bytes * @param : ToDo * @Retval: True - if the operation is successful * False - if the operation isn't successful ******************************************************************************/ bool HW_UART_Modem_SendBytes(const char *pData, uint16_t size) { if (HAL_UART_Transmit(&hxcUart, (uint8_t *)pData, size, 5000) != HAL_OK) { return false; } return true; } void HW_UART_Modem_Ready(void) { hxcUart.gState = HAL_UART_STATE_READY; hxcUart.RxState = HAL_UART_STATE_READY; } /****************************************************************************** * @brief Store in ring buffer the received character * @param none * @retval none ******************************************************************************/ static void receive(char rx) { int next_free; /** no need to clear the RXNE flag because it is auto cleared by reading the data*/ uart_context.buffRx[uart_context.rx_idx_free] = rx; next_free = (uart_context.rx_idx_free + 1) % sizeof(uart_context.buffRx); if (next_free != uart_context.rx_idx_toread) { /* this is ok to read as there is no buffer overflow in input */ uart_context.rx_idx_free = next_free; } // else // { // /* force the end of a command in case of overflow so that we can process it */ // uart_context.buffRx[uart_context.rx_idx_free] = '\r'; // PRINTF("uart_context.buffRx buffer overflow %d\r\n"); // } } /** * @} */ /** * @} */ /************************ (C) COPYRIGHT Haxiot *****END OF FILE****/