Micro2020/assignment_3/Libraries/drivers/thermostat_shield.c

633 lines
19 KiB
C

/*!
* \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 : <cchoutou@ece.auth.gr>
*/
#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 (<package_size> 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<size ; ++i) {
r = deque08_pop_front (&_com_rxq, &b);
data[i] = b;
}
return i;
}