/*! * \file * thermostat_shield.c * \brief * Nucleo thermostat shield port file. This file contain the implementation of driver * calls for the shield. * * Author: Christos Choutouridis AEM: 8997 * email : */ #include "thermostat_shield.h" /* * =============== Digital I/O =============== */ static void SHIELD_LCD_Port_Init (void); static void SHIELD_LED_Port_Init (void); static void SHIELD_BRIDGE_Port_Init (void); static void SHIELD_SR04_Port_Init (void); /* * =============== LCD =============== * LCD_BD4 -- D8 -- PA9 * LCD_BD5 -- D7 -- PA8 * LCD_BD6 -- D6 -- PB10 * LCD_BD7 -- D5 -- PB4 * LCD_RS -- D15 -- PB8 * LCD_EN -- D14 -- PB9 * LCD_BL -- D2 -- PA10 */ static void SHIELD_LCD_Port_Init (void) { GPIO_InitTypeDef GPIO_InitType; __HAL_RCC_GPIOA_CLK_ENABLE (); __HAL_RCC_GPIOB_CLK_ENABLE (); GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitType.Speed = GPIO_SPEED_LOW; GPIO_InitType.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; HAL_GPIO_Init(GPIOA, &GPIO_InitType); GPIO_InitType.Pin = GPIO_PIN_4 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; HAL_GPIO_Init(GPIOB, &GPIO_InitType); } void SHIELD_LCD_DB4 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_9, en); } void SHIELD_LCD_DB5 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_8, en); } void SHIELD_LCD_DB6 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_10, en); } void SHIELD_LCD_DB7 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_4, en); } void SHIELD_LCD_RS (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_8, en); } void SHIELD_LCD_EN (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_9, en); } void SHIELD_LCD_BL (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_10, en); } /* * =============== LED =============== * LED0 -- D4 -- PB5 * LED1 -- D3 -- PB3 */ static void SHIELD_LED_Port_Init (void) { GPIO_InitTypeDef GPIO_InitType; __HAL_RCC_GPIOB_CLK_ENABLE (); GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitType.Speed = GPIO_SPEED_LOW; GPIO_InitType.Pin = GPIO_PIN_3 | GPIO_PIN_5; HAL_GPIO_Init(GPIOB, &GPIO_InitType); } void SHIELD_LED0 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_5, on); } void SHIELD_LED1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_3, on); } /* * =============== BRIDGE =============== * BR1 -- D10 -- PB6 * BR2 -- D9 -- PC7 */ static void SHIELD_BRIDGE_Port_Init (void) { GPIO_InitTypeDef GPIO_InitType; __HAL_RCC_GPIOB_CLK_ENABLE (); __HAL_RCC_GPIOC_CLK_ENABLE (); GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitType.Speed = GPIO_SPEED_LOW; GPIO_InitType.Pin = GPIO_PIN_6; HAL_GPIO_Init(GPIOB, &GPIO_InitType); GPIO_InitType.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOC, &GPIO_InitType); } void SHIELD_BR1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_6, on); } void SHIELD_BR2 (uint8_t on) { _DOUTx(GPIOC, GPIO_PIN_7, on); } /* * =============== SR04 =============== * TRIG -- D11 -- PA7 * ECHO -- D12 -- PA6 */ static void SHIELD_SR04_Port_Init (void) { GPIO_InitTypeDef GPIO_InitType; __HAL_RCC_GPIOA_CLK_ENABLE (); GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitType.Speed = GPIO_SPEED_LOW; GPIO_InitType.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOA, &GPIO_InitType); GPIO_InitType.Mode = GPIO_MODE_INPUT; GPIO_InitType.Pull = GPIO_NOPULL; GPIO_InitType.Pin = GPIO_PIN_6; HAL_GPIO_Init(GPIOA, &GPIO_InitType); } void SHIELD_TRIG (uint8_t on) { _DOUTx(GPIOA, GPIO_PIN_7, on); } uint8_t SHIELD_ECHO (void) { return _DINx (GPIOA, GPIO_PIN_6); } /* * ============= 1 Wire UART6 (AF08)=============== * 1W_Tx -- PA11 (OD+PU) * 1W_Rx -- PA12 (I) */ static UART_HandleTypeDef h1w_uart; /*! * \brief * This function handles UART Communication Timeout. * \param huart: Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * \param Flag: specifies the UART flag to check. * \param Status: The new Flag status (SET or RESET). * \param Timeout: Timeout duration * \return HAL status */ static HAL_StatusTypeDef _WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Timeout) { uint32_t tickstart = HAL_GetTick(); if (Status != RESET) Status = SET; /* Catch wrong Status */ /* Wait until flag is on FlagStatus Status */ while (__HAL_UART_GET_FLAG (huart, Flag) == Status) { if ((Timeout == 0) || ((HAL_GetTick() - tickstart ) > Timeout)) { /* Give up */ huart->gState= HAL_UART_STATE_READY; /* Mark Timeout as ready */ __HAL_UNLOCK (huart); /* Process Unlocked */ return HAL_TIMEOUT; /* Return the TIMEOUT */ } } return HAL_OK; } /*! * \brief * Initialize 1-Wire UART to 8bits, no parity, 1 stop, so it can * be used for 1-Wire communication * \return The status of the operation * \arg LLD_OK Success * \arg LLD_ERROR The Init failed. */ static LLD_Status_en _1W_UART_Init (void) { _1WIRE_UART_CLK_ENABLE (); // Enable 1-wire's USART clock /* * USART configured as follows: * - Word Length = 8 Bits * - Stop Bit = One Stop bit * - Parity = No parity * - BaudRate = _1WIRE_UART_INIT_BR baud * - Hardware flow control disabled (RTS and CTS signals) */ h1w_uart.Instance = _1WIRE_UART_INSTANCE; h1w_uart.Init.BaudRate = _1WIRE_UART_INIT_BR; h1w_uart.Init.WordLength = UART_WORDLENGTH_8B; h1w_uart.Init.StopBits = UART_STOPBITS_1; h1w_uart.Init.Parity = UART_PARITY_NONE; h1w_uart.Init.Mode = UART_MODE_TX_RX; if (HAL_UART_Init(&h1w_uart) != HAL_OK) return LLD_ERROR; return LLD_OK; } /*! * Init the KEY 1wire interface and allocate all resources for it * \return The status of the operation * \arg LLD_OK Success * \arg LLD_ERROR The Init failed. */ LLD_Status_en SHIELD_1W_Init (void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE (); GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = GPIO_AF8_USART6; HAL_GPIO_WritePin (GPIOA, GPIO_InitStruct.Pin, GPIO_PIN_SET); HAL_GPIO_Init (GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12; //GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Alternate = GPIO_AF8_USART6; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; /*^ * Mark as alternate because HAL_GPIO_Init () * can not configure Input + alternate */ HAL_GPIO_Init (GPIOA, &GPIO_InitStruct); return _1W_UART_Init (); } /*! * \brief * Set a Baudrate to the UART, to use for 1-Wire communication * \param br The desired baudrate * \return The status of the operation (part of toolbox) * \arg DRV_ERROR Fail * \arg DRV_READY Success */ drv_status_en SHIELD_1W_UART_BR (uint32_t br) { /* * Keep USART configured as already set by Init: * - Word Length = 8 Bits * - Stop Bit = One Stop bit * - Parity = No parity * - Hardware flow control disabled (RTS and CTS signals) */ if (! IS_UART_BAUDRATE (br) ) return DRV_ERROR; h1w_uart.Init.BaudRate = br; /* Check the Over Sampling */ if(h1w_uart.Init.OverSampling == UART_OVERSAMPLING_8) { /*------- UART-associated USART registers setting : BRR Configuration ------*/ if((h1w_uart.Instance == USART1)){ h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate); } else { h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate); } } else { /*------- UART-associated USART registers setting : BRR Configuration ------*/ if((h1w_uart.Instance == USART1)) { h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate); } else { h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate); } } return DRV_READY; } /*! * \brief * Read-Write functionality. We use the following USART configuration. * - Word Length = 8 Bits * - Stop Bit = One Stop bit * - Parity = No parity * \return The byte received. On failure return 0xFFFF (bus released state) * \note * Due to the nature of the PCB, the received byte is the actual bus * condition during the communication frame (time slot) */ uint16_t SHIELD_1W_RW (uint8_t byte) { if (h1w_uart.Init.WordLength != UART_WORDLENGTH_8B) return (uint8_t)0xFFFF; if (h1w_uart.Init.Parity != UART_PARITY_NONE) return (uint8_t)0xFFFF; if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TXE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK) return 0x1FF; WRITE_REG (h1w_uart.Instance->DR, (byte & (uint8_t)0xFF)); if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TC, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK) return 0x2FF; //if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_RXNE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK) // return 0xFFFF; return (uint8_t)(h1w_uart.Instance->DR & (uint8_t)0x00FF); } /*! * \brief * Receive functionality. We use USART blocking mode. * \return The byte received. On failure return 0xFF (bus released state) * \note * Due to the nature of the PCB, the received byte is the actual bus * condition during the communication frame (time slot) */ uint8_t SHIELD_1W_Rx (void) { uint8_t rx; if (HAL_UART_Receive (&h1w_uart, &rx, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK) rx = 0xFF; return rx; } /*! * \brief * Transmit functionality. We use USART blocking mode. * \return The status of transition * \arg 0 Success * \arg 1 Fail */ uint8_t SHIELD_1W_Tx (uint8_t byte) { if (HAL_UART_Transmit (&h1w_uart, &byte, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK) return 1; return 0; } LLD_Status_en SHIELD_Init (void) { SHIELD_LCD_Port_Init (); SHIELD_LED_Port_Init (); SHIELD_BRIDGE_Port_Init (); SHIELD_SR04_Port_Init (); SHIELD_1W_Init (); COM_Init (); return LLD_OK; } /* * ============= Serial console UART2 (AF07)=============== * COM_Tx -- PA2 (PP) * COM_Rx -- PA3 (I) */ static UART_HandleTypeDef com_huart; static deque08_t _com_rxq; static byte_t _com_rxbuffer[COM_BUFFER_SIZE]; /*! * \brief * Called from USART IRQ to put the read character to queue * \param Pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * * \return The status of the operation * \arg HAL_ERROR Fail * \arg HAL_OK Success */ static HAL_StatusTypeDef _UART_read_data (UART_HandleTypeDef *huart, deque08_t *q) { uint8_t r; __HAL_LOCK(huart); /* * We don't try to receive valid data while the USART is * locked from transmitter. It's OK ;) */ /* Receive data based on Word length and parity */ switch (huart->Init.WordLength) { default: case UART_WORDLENGTH_8B: if(huart->Init.Parity == UART_PARITY_NONE) r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF); else r = (uint8_t)(huart->Instance->DR & (uint16_t)0x007F); break; case UART_WORDLENGTH_9B: if(huart->Init.Parity == UART_PARITY_NONE) { r = (uint8_t)(huart->Instance->DR & (uint16_t)0x01FF); __HAL_UNLOCK(huart); return HAL_ERROR; /* Not supported Configuration */ } else r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF); break; } deque08_push_back (q, r); /*!< * \note * We queue the received bytes. The user application MUST * read the queue in a regular basis, or else this IRQ will * find queue full and we will have data loss. */ __HAL_UNLOCK(huart); return HAL_OK; } void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { __HAL_UART_CLEAR_PEFLAG (huart); huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState = HAL_UART_STATE_READY; /* * Clear all the error flag at once, * Set USART READY for re-start, * Error Callback */ } /*! * \brief * USART serial handler. Pushes every received character to a queue. * * In the IRQ handler there is only Rx functionality provided by this driver. * The Error handling call the HAL's callback (which are empty) * The Tx part, is not implemented */ void USART2_IRQHandler (void) { uint32_t tmp_flag = 0, tmp_it_source = 0; // ======= Error handler ========= if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_PE)) != RESET) && ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_PE)) != RESET)) { /* UART parity error interrupt occurred */ com_huart.ErrorCode |= HAL_UART_ERROR_PE; } if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_FE)) != RESET) && ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_ERR)) != RESET)) { /* UART frame error interrupt occurred */ com_huart.ErrorCode |= HAL_UART_ERROR_FE; } if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_NE)) != RESET) && (tmp_it_source != RESET)){ /* UART noise error interrupt occurred */ com_huart.ErrorCode |= HAL_UART_ERROR_NE; } if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_ORE)) != RESET) && (tmp_it_source != RESET)){ /* USART Over-Run interrupt occurred */ com_huart.ErrorCode |= HAL_UART_ERROR_ORE; } if(com_huart.ErrorCode != HAL_UART_ERROR_NONE) { HAL_UART_ErrorCallback (&com_huart); } // ====== Get Data ========= if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_RXNE)) != RESET) && ((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_RXNE)) != RESET)) { // Read byte _UART_read_data (&com_huart, &_com_rxq); // Don't check return status } } /*! * \brief * Initialize the UART and UART IRQ handler * \return The status of the operation * \arg LLD_ERROR Fail * \arg LLD_OK Success */ static LLD_Status_en _COM_UART_Init (void) { /* * Enable UART clock */ _COM_CLK_ENABLE(); deque08_link_buffer (&_com_rxq, _com_rxbuffer); deque08_set_capacity (&_com_rxq, COM_BUFFER_SIZE); deque08_init (&_com_rxq); /* * USART configured as follows: * - Word Length = 8 Bits * - Stop Bit = One Stop bit * - Parity = No parity * - BaudRate = COM_BAUDRATE baud * - Hardware flow control disabled (RTS and CTS signals) */ com_huart.Instance = COM_UART_INSTANCE; com_huart.Init.BaudRate = COM_UART_BAUDRATE; com_huart.Init.WordLength = UART_WORDLENGTH_8B; com_huart.Init.StopBits = UART_STOPBITS_1; com_huart.Init.Parity = UART_PARITY_NONE; com_huart.Init.Mode = UART_MODE_TX_RX; if (HAL_UART_Init(&com_huart) != HAL_OK) return LLD_ERROR; /* * Enable IRQ for Rx * Tx IRQ enabled by COM_transmit () */ HAL_NVIC_SetPriority (COM_UART_IRQ, 0x0D, 0); HAL_NVIC_EnableIRQ (COM_UART_IRQ); /* Enable the UART Data Register not empty Interrupt */ __HAL_UART_ENABLE_IT(&com_huart, UART_IT_RXNE); /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ //__HAL_UART_ENABLE_IT(&com_huart, UART_IT_ERR); return LLD_OK; } /*! * Initialize the COM dedicated I/O and allocate resources * \return The status of the operation */ LLD_Status_en COM_Init (void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE (); GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init (GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // GPIO_InitStruct.Pull = GPIO_NOPULL; // GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init (GPIOA, &GPIO_InitStruct); return _COM_UART_Init(); } /*! * \brief * Set UART baudrate * \param br The desired baudrate * \return The status of the operation * \arg LLD_ERROR Fail * \arg LLD_OK Success */ LLD_Status_en COM_baudrate (uint32_t br) { // Change only the Baudrate com_huart.Init.BaudRate = br; if (HAL_UART_Init(&com_huart) != HAL_OK) return LLD_ERROR; return LLD_OK; } /*! * \brief * USART's putchar functionality to link with io system * This function is compatible with putchar() in "stdio.h" */ int COM_putchar (char c) { if (_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, RESET, COM_UART_PUTCHAR_TIMEOUT) != HAL_OK) return 0xFFFF; WRITE_REG (COM_UART_INSTANCE->DR, (c & (uint8_t)0xFF)); /*!< * \note * The sequence: * - Read operation to USART_SR register [USART_GetFlagStatus()] * - Write operation to USART_DR register [USART_SendData()] * clears the TC Flag * * The TXE Flag is cleared by the write operation to USART_DR register * [USART_SendData()] */ return (int)c; } /*! * \brief * USART's getchar functionality to link with io system * This function is compatible with getchar() in "stdio.h" */ int COM_getchar (void) { clock_t mark = clock (); clock_t to = COM_UART_GETCHAR_TIMEOUT*get_freq(); clock_t now; byte_t r=0; while (deque08_pop_front (&_com_rxq, &r) == 0) { now = clock (); if (_CLOCK_DIFF(now, mark) >= to) return 0; } return r; } /*! * \brief * Transmit functionality to link with io system * This function is compatible with htp tx functionality * * \param data Pointer to data buffer * \param size Size of buffer (number of bytes) * \return The number of bytes to transmit */ int COM_Transmit (uint8_t *data, int size) { int r = size; while (size--) { //queue08_push (&_com_txq, (byte_t)*data); COM_putchar(*data++); } _WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, SET, COM_UART_PUTCHAR_TIMEOUT); return r; } /*! * \brief * Check receive functionality synchronized to IRQ * This function is compatible with htp rx functionality * * \return The number of bytes on queue ( indicates done) */ int COM_CheckReceive (void) { return deque08_size (&_com_rxq); } /*! * \brief * Receive flush functionality to link with io system * This function is compatible with htp rx functionality * * \param data Pointer to data buffer * \param size Size of buffer (number of bytes) * \return The number of received bytes */ void COM_ReceiveFlush (void) { deque08_flush (&_com_rxq); } /*! * \brief * Receive functionality to link with io system * This function is compatible with htp rx functionality * * \param data Pointer to data buffer * \param size Size of buffer (number of bytes) * \return The number of received bytes */ int COM_Receive (uint8_t *data, int size) { int i; uint8_t r=1, b; for (i=0 ; r !=0 && i