@@ -11,6 +11,7 @@ deliver/ | |||||
*.ld | *.ld | ||||
Debug/ | Debug/ | ||||
Release/ | Release/ | ||||
*.launch | |||||
# Keil related | # Keil related | ||||
Keil/ | Keil/ | ||||
@@ -0,0 +1,313 @@ | |||||
/*! | |||||
* \file | |||||
* NUCLEO_F401RE.h | |||||
* \brief | |||||
* Nucleo F401RE port file. This file contain the implementation of driver | |||||
* calls for F401RE board. | |||||
* | |||||
* Created on: May 23, 2020 | |||||
* Author: Christos Choutouridis AEM: 8997 | |||||
* email : <cchoutou@ece.auth.gr> | |||||
*/ | |||||
#include "NUCLEO_F401RE.h" | |||||
/* | |||||
* =============== System =============== | |||||
*/ | |||||
static clock_t volatile __ticks; //!< CPU time | |||||
static time_t volatile __now; //!< Time in UNIX seconds past 1-Jan-70 | |||||
static clock_t volatile __sys_freq; //!< The CPU's time frequency (SysTick freq) | |||||
/*! | |||||
* \brief | |||||
* This is the SysTick ISR, micro-system time base service for CPU time. | |||||
* \note | |||||
* This service implements the SysTick callback function in order | |||||
* to provide micro system - os like functionalities to an application | |||||
* without RTOS | |||||
*/ | |||||
void SysTick_Handler(void) { | |||||
// Time | |||||
++__ticks; | |||||
if ( !(__ticks % __sys_freq ) ) | |||||
++__now; // Do not update __now when we have external time system | |||||
} | |||||
/*! | |||||
* \brief This function configures the source of the time base. | |||||
* The time source is configured to have 1ms time base with a dedicated | |||||
* Tick interrupt priority. | |||||
* \param sf Tick interrupt frequency. | |||||
* \retval HAL status | |||||
*/ | |||||
__weak HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf) { | |||||
SystemCoreClockUpdate (); | |||||
/* Configure the SysTick to have interrupt in sf time basis */ | |||||
if (SysTick_Config (SystemCoreClock/sf) != 0) | |||||
return HAL_ERROR; | |||||
__sys_freq = sf; | |||||
/*Configure the SysTick IRQ priority */ | |||||
NVIC_SetPriority (SysTick_IRQn, 3U); | |||||
/* Return function status */ | |||||
return HAL_OK; | |||||
} | |||||
/*! | |||||
* Select the system frequency without calling the Setting functionality | |||||
* \param sf The desired value | |||||
* \return The desired value (enable chaining) | |||||
*/ | |||||
__INLINE clock_t HAL_SelectSysTickFreq (clock_t sf){ | |||||
return __sys_freq =sf; | |||||
} | |||||
/*! | |||||
* \brief Get the __sys_freq. | |||||
*/ | |||||
__INLINE clock_t HAL_GetSysTickFreq (void){ | |||||
return __sys_freq; | |||||
} | |||||
/*! | |||||
* \brief Reconfigure the SysTick and update __sys_freq | |||||
* \param sf Tick interrupt frequency (CPU time) | |||||
* \return status of the operation | |||||
* \arg 0 Success | |||||
* \arg 1 Fail | |||||
*/ | |||||
int HAL_SetSysTickFreq (clock_t sf) { | |||||
/*Configure the SysTick to have interrupt in sf time basis*/ | |||||
if (__sys_freq != sf) { | |||||
// Time base configuration | |||||
SystemCoreClockUpdate (); | |||||
if (SysTick_Config ( (SystemCoreClock>>3)/sf) != 0) | |||||
return 1; | |||||
else { | |||||
__sys_freq = sf; | |||||
return 0; | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
// Take over control of SysTick from HAL library | |||||
//! disable HAL_InitTick implementation | |||||
HAL_StatusTypeDef | |||||
HAL_InitTick(uint32_t TickPriority) { return HAL_OK; } | |||||
//! Chain GetTick to our implementation | |||||
uint32_t HAL_GetTick(void) { return clock(); } | |||||
/*! | |||||
* \brief This function provides minimum delay (in CPU time) based | |||||
* on variable incremented. | |||||
* \param Delay specifies the delay time length, in CPU time. | |||||
* \note | |||||
* uint32_t is implicitly convertible to clock_t and vice versa. | |||||
*/ | |||||
void HAL_Delay(uint32_t Delay) { | |||||
uint32_t tickstart = clock(); | |||||
while((clock() - tickstart) < Delay) | |||||
; | |||||
} | |||||
/* | |||||
* ================ Jiffies ====================== | |||||
*/ | |||||
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) { | |||||
uint32_t psc=0; | |||||
JF_TIMER_CLK_ENABLE(); | |||||
SystemCoreClockUpdate (); | |||||
if (jf_freq) | |||||
psc = SystemCoreClock / jf_freq - 1; | |||||
if (psc < 0xFFFF) JF_TIMER->PSC = psc; | |||||
else return 1; | |||||
if (jiffies < 0xFFFF) JF_TIMER->ARR = jiffies; | |||||
else return 1; | |||||
JF_TIMER->CR1 |= TIM_CR1_CEN; | |||||
return 0; | |||||
} | |||||
/* | |||||
* ======== OS like Functionalities ============ | |||||
*/ | |||||
//! SysTick frequency getter | |||||
__INLINE clock_t get_freq (void) { | |||||
return __sys_freq; | |||||
} | |||||
//! SysTick frequency setter | |||||
//! \return True on failure | |||||
int set_freq (clock_t sf) { | |||||
return HAL_SetSysTickFreq (sf); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* determines the processor time. | |||||
* \return | |||||
* the implementation's best approximation to the processor time | |||||
* used by the program since program invocation. The time in | |||||
* seconds is the value returned divided by the value of the macro | |||||
* CLK_TCK or CLOCKS_PER_SEC | |||||
*/ | |||||
__INLINE clock_t clock (void) { | |||||
return (clock_t) __ticks; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Set the processor time used. | |||||
* \param c The new CPU time value | |||||
* \return | |||||
* The implementation's best approximation to the processor time | |||||
* used by the program since program invocation. The time in | |||||
* seconds is the value returned divided by the value of the macro | |||||
* CLK_TCK or CLOCKS_PER_SEC | |||||
*/ | |||||
clock_t setclock (clock_t c) { | |||||
return __ticks = c; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* determines the current calendar time. The encoding of the value is | |||||
* unspecified. | |||||
* \return | |||||
* The implementations best approximation to the current calendar | |||||
* time. If timer is not a null pointer, the return value | |||||
* is also assigned to the object it points to. | |||||
*/ | |||||
time_t time (time_t *timer) { | |||||
if (timer) | |||||
*timer = (time_t)__now; | |||||
return (time_t)__now; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Sets the system's idea of the time and date. The time, | |||||
* pointed to by t, is measured in seconds since the Epoch, 1970-01-01 | |||||
* 00:00:00 +0000 (UTC). | |||||
* \param t Pointer to new system's time and date. | |||||
* \return On success, zero is returned. On error, -1 is returned | |||||
*/ | |||||
int settime (const time_t *t) { | |||||
if (t) { | |||||
__now = *t; | |||||
return 0; | |||||
} | |||||
else | |||||
return -1; | |||||
} | |||||
/* | |||||
* ============== Cycle count ============== | |||||
*/ | |||||
/*! | |||||
* Initialize CPU cycle measurement functionality based on DBG | |||||
* \return The status of the operation | |||||
* \arg LLD_OK Success | |||||
* \arg LLD_ERROR Failure | |||||
*/ | |||||
LLD_Status_en CYCLE_Init (void) { | |||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // enable trace | |||||
//DWT->LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers | |||||
DWT->CYCCNT = 0; // clear DWT cycle counter | |||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable DWT cycle counter | |||||
return LLD_OK; | |||||
} | |||||
//! CPU cycle getter | |||||
__INLINE clock_t CYCLE_Get (void) { | |||||
return (clock_t)DWT->CYCCNT; | |||||
} | |||||
//! Helper digital input pin getter | |||||
__INLINE uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin) { | |||||
return ((port->IDR & pin) != 0) ? 1:0; | |||||
} | |||||
//! Helper digital output pin setter | |||||
__INLINE uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st) { | |||||
if (st) port->BSRR = (uint32_t)pin; | |||||
else port->BSRR = (uint32_t)pin << 16; | |||||
return st; | |||||
} | |||||
/* | |||||
* =============== Digital I/O =============== | |||||
* BTN -- PC13 | |||||
* LED -- PA5 (SB42 is in place) [SB29: PB13] | |||||
*/ | |||||
/*! | |||||
* Initialize GPIO port pins for Nucleo Board | |||||
* \return The status of the operation | |||||
* \arg LLD_OK Success | |||||
* \arg LLD_ERROR Failure | |||||
*/ | |||||
LLD_Status_en NUCLEO_Port_Init (void) { | |||||
GPIO_InitTypeDef GPIO_InitType; | |||||
// Enable Port clock | |||||
__HAL_RCC_GPIOA_CLK_ENABLE (); | |||||
__HAL_RCC_GPIOC_CLK_ENABLE (); | |||||
// BTN port configuration | |||||
GPIO_InitType.Mode = GPIO_MODE_INPUT; | |||||
GPIO_InitType.Pin = GPIO_PIN_13; | |||||
GPIO_InitType.Pull = GPIO_NOPULL; | |||||
HAL_GPIO_Init(GPIOC, &GPIO_InitType); | |||||
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP; | |||||
GPIO_InitType.Speed = GPIO_SPEED_LOW; | |||||
GPIO_InitType.Pin = GPIO_PIN_5; | |||||
HAL_GPIO_Init(GPIOA, &GPIO_InitType); | |||||
return LLD_OK; | |||||
} | |||||
//! Nucleo's user button reader | |||||
uint8_t NUCLEO_BTN (void) { | |||||
return _DINx (GPIOC, GPIO_PIN_13); | |||||
} | |||||
//! Nucleo's LD2 led setter | |||||
void NUCLEO_LED (uint8_t on) { | |||||
_DOUTx(GPIOA, GPIO_PIN_5, on); | |||||
} | |||||
/*! Low level driver init functionality | |||||
* \return The status of the operation | |||||
* \arg LLD_OK Success | |||||
* \arg LLD_ERROR Failure | |||||
*/ | |||||
LLD_Status_en NUCLEO_Init (clock_t sys_freq) { | |||||
HAL_Init(); | |||||
HAL_SysTick_Init (sys_freq); | |||||
CYCLE_Init (); | |||||
NUCLEO_Port_Init (); | |||||
return LLD_OK; | |||||
} |
@@ -0,0 +1,158 @@ | |||||
/*! | |||||
* \file | |||||
* NUCLEO_F401RE.h | |||||
* \brief | |||||
* Nucleo F401RE port file. This file contain the implementation of driver | |||||
* calls for F401RE board. | |||||
* | |||||
* Created on: May 23, 2020 | |||||
* Author: Christos Choutouridis AEM: 8997 | |||||
* email : <cchoutou@ece.auth.gr> | |||||
*/ | |||||
#ifndef NUCLEO_F401RE_H_ | |||||
#define NUCLEO_F401RE_H_ | |||||
#include <stm32f4xx.h> | |||||
#include <stm32f4xx_hal.h> | |||||
#include <core_cm4.h> | |||||
/* | |||||
* ========= Data types ======== | |||||
*/ | |||||
//! Driver status return type | |||||
typedef enum { | |||||
LLD_OK = 0, //!< Indicate successful operation | |||||
LLD_ERROR //!< Indicate Error | |||||
}LLD_Status_en; | |||||
typedef uint8_t din_t; | |||||
//typedef int adc_t; | |||||
#define OFF (0) | |||||
#define ON (!OFF) | |||||
#ifndef FALSE | |||||
#define FALSE (0) | |||||
#endif | |||||
#ifndef TRUE | |||||
#define TRUE (!FALSE) | |||||
#endif | |||||
/* | |||||
* =============== System =============== | |||||
*/ | |||||
#if defined ( __GNUC__ ) && !defined (__CC_ARM) | |||||
#include <sys/types.h> | |||||
#endif | |||||
#include <limits.h> | |||||
/* | |||||
* Also defined in types.h | |||||
*/ | |||||
#ifndef _CLOCK_T_ | |||||
#if defined (__CC_ARM) | |||||
#define _CLOCK_T_ unsigned int | |||||
#else | |||||
#define _CLOCK_T_ unsigned long | |||||
#endif | |||||
typedef _CLOCK_T_ clock_t; /*!< CPU time type */ | |||||
#endif | |||||
#ifndef _TIME_T_ | |||||
#if defined (__CC_ARM) | |||||
#define _TIME_T_ unsigned int | |||||
#else | |||||
#define _TIME_T_ unsigned long | |||||
#endif | |||||
typedef _TIME_T_ time_t; /*!< date/time in unix secs past 1-Jan-70 type for 68 years*/ | |||||
#endif | |||||
/* | |||||
* Helper macros | |||||
*/ | |||||
#define _CLOCK_T_MAX_VALUE_ (ULONG_MAX) //!< Helper macro for maximum signed CPU time calculations | |||||
/*! | |||||
* Calculate the positive time difference of _t2_ and _t1_, where | |||||
* _t1_, _t2_ are clock_t values | |||||
* \note | |||||
* _t2_ event comes is AFTER _t1_ | |||||
* | |||||
* ex: | |||||
* 0 1 2 3 4 5 6 7 8 9 | |||||
* ^ ^ | |||||
* | | | |||||
* a b | |||||
* | |||||
* if : t1=a, t2=b then dt = b-a = t2 - t1 | |||||
* if : t1=b, t2=a then dt = 9 - (b-a) + 1 = UMAX - (t1-t2) + 1 | |||||
* | |||||
*/ | |||||
#define _CLOCK_DIFF(_t2_, _t1_) ( ((_t2_)>(_t1_)) ? ((_t2_)-(_t1_)) : (_CLOCK_T_MAX_VALUE_ - ((_t1_) - (_t2_)) + 1) ) | |||||
/* | |||||
* CPU time macros | |||||
*/ | |||||
#define msec2CPUtime(_ms_) (((_ms_) * get_freq()) / 1000) | |||||
#define sec2CPUtime(_s_) ((_s_) * get_freq()) | |||||
#define CPUtime2msec(_t_) (((_t_) * 1000) / get_freq()) | |||||
#define CPUtime2sec(_t_) ((_t_) / get_freq()) | |||||
HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf); | |||||
clock_t HAL_SelectSysTickFreq (clock_t sf); | |||||
clock_t HAL_GetSysTickFreq (void); | |||||
int HAL_SetSysTickFreq (clock_t sf); | |||||
/* | |||||
* ================ Jiffies ===================== | |||||
*/ | |||||
#define JF_TIMER TIM5 | |||||
#define JF_TIM_CLOCK_FREQ (1000000) //1MHz it's OK | |||||
#define JF_TIM_VALUE (JF_TIMER->CNT) | |||||
#define JF_TIMER_CLK_ENABLE __HAL_RCC_TIM5_CLK_ENABLE | |||||
int JF_setfreq (uint32_t jf_freq, uint32_t jiffies); | |||||
/* | |||||
* OS like Functionalities | |||||
*/ | |||||
clock_t get_freq (void); | |||||
int set_freq (clock_t sf); | |||||
clock_t clock (void); | |||||
clock_t setclock (clock_t c); | |||||
time_t time (time_t *timer); | |||||
int settime (const time_t *t); | |||||
/* | |||||
* ============== Cycle count ============== | |||||
*/ | |||||
LLD_Status_en CYCLE_Init (void); | |||||
clock_t CYCLE_Get (void); | |||||
uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin); | |||||
uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st); | |||||
/* | |||||
* =============== Digital I/O =============== | |||||
* BTN -- PC13 | |||||
* LED -- PA5 (SB42 is in place) [SB29: PB13] | |||||
*/ | |||||
LLD_Status_en NUCLEO_Port_Init (void); | |||||
uint8_t NUCLEO_BTN (void); | |||||
void NUCLEO_LED (uint8_t on); | |||||
/* | |||||
* ============= Board Init ============== | |||||
*/ | |||||
LLD_Status_en NUCLEO_Init (clock_t sys_freq); | |||||
#endif /* NUCLEO_F401RE_H_ */ |
@@ -0,0 +1,507 @@ | |||||
/*! | |||||
* \file alcd.c | |||||
* \brief | |||||
* A target independent Alpharithmetic LCD driver | |||||
* | |||||
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#include "alcd.h" | |||||
static int _inc_x (alcd_t *alcd); | |||||
static int _dec_x (alcd_t *alcd); | |||||
static void _inc_y (alcd_t *alcd); | |||||
static void _dec_y (alcd_t *alcd); | |||||
static void _set_bus (alcd_t *alcd, int8_t db); | |||||
static void _write_data (alcd_t *alcd, int8_t data); | |||||
static void _command (alcd_t *alcd, uint8_t c); | |||||
static void _character (alcd_t *alcd, uint8_t c); | |||||
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y); | |||||
/*! | |||||
* \brief | |||||
* increase cursor's x position. Positions start from 1. | |||||
* If the cursor loops returns 1, else returns 0. | |||||
* \param alcd pointer to active alcd. | |||||
* \return Change line status | |||||
*/ | |||||
static int _inc_x (alcd_t *alcd) { | |||||
int ret=0; | |||||
if (++alcd->c.x > alcd->columns) { | |||||
alcd->c.x = 1; | |||||
ret = 1; | |||||
} | |||||
return ret; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Decrease cursor's x position. Positions start from 1. | |||||
* If the cursor loops returns 1, else returns 0. | |||||
* \param alcd pointer to active alcd. | |||||
* \return none | |||||
*/ | |||||
static int _dec_x (alcd_t *alcd) { | |||||
int ret = 0; | |||||
if (--alcd->c.x < 1) { | |||||
alcd->c.x = alcd->columns; | |||||
ret = 1; | |||||
} | |||||
return ret; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* increase cursor's y position. Positions start from 1. | |||||
* \param alcd pointer to active alcd. | |||||
* \return none | |||||
*/ | |||||
static void _inc_y (alcd_t *alcd) { | |||||
if (++alcd->c.y > alcd->lines) { | |||||
alcd->c.y = 1; | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Decrease cursor's y position. Positions start from 1. | |||||
* \param alcd pointer to active alcd. | |||||
* \return none | |||||
*/ | |||||
static void _dec_y (alcd_t *alcd) { | |||||
if (--alcd->c.y < 1) { | |||||
alcd->c.y = alcd->lines; | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Update the bus I/O and send it to the device. | |||||
* \param alcd pointer to active alcd. | |||||
* \param db the bus data. | |||||
* \return none | |||||
*/ | |||||
static void _set_bus (alcd_t *alcd, int8_t db) | |||||
{ | |||||
alcd->io.db4 (db & 0x01); //Update port | |||||
alcd->io.db5 (db & 0x02); | |||||
alcd->io.db6 (db & 0x04); | |||||
alcd->io.db7 (db & 0x08); | |||||
jf_delay_us (10); // Wait to settle | |||||
alcd->io.en (1); // Pulse out the data | |||||
jf_delay_us (10); | |||||
alcd->io.en (0); | |||||
jf_delay_us (10); // Data hold | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Write the byte date to the bus using _set_bus () | |||||
* \param alcd pointer to active alcd. | |||||
* \param data the data byte. | |||||
* \return none | |||||
*/ | |||||
static void _write_data (alcd_t *alcd, int8_t data) | |||||
{ | |||||
_set_bus (alcd, data >> 4); | |||||
_set_bus (alcd, data & 0x0F); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Send a command to alcd | |||||
* \param alcd pointer to active alcd. | |||||
* \param c the command byte. | |||||
* \return none | |||||
*/ | |||||
static void _command (alcd_t *alcd, uint8_t c) | |||||
{ | |||||
alcd->io.rs(0); // Enter command mode | |||||
jf_delay_us (100); // Wait | |||||
_write_data (alcd, c); // Send | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Send a character to alcd | |||||
* \param alcd pointer to active alcd. | |||||
* \param c the character byte. | |||||
* \return none | |||||
*/ | |||||
static void _character (alcd_t *alcd, uint8_t c) | |||||
{ | |||||
alcd->io.rs(1); // Enter character mode | |||||
jf_delay_us (100); // Wait | |||||
_write_data (alcd, c); // Send | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Set the Cursor to LCD's position line (y), column (x) starts from 1,2,...n | |||||
* \param alcd pointer to active alcd. | |||||
* \param x the x position. | |||||
* \param y the y position. | |||||
* \return none | |||||
*/ | |||||
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y) | |||||
{ | |||||
uint8_t cmd; | |||||
alcd->c.x = x; // Update alcd data | |||||
alcd->c.y = y; | |||||
// Calculate address | |||||
switch (y) { | |||||
default: | |||||
case 1: cmd = 0x0; break; | |||||
case 2: cmd = 0x40; break; | |||||
case 3: cmd = 0x0 + alcd->columns; break; | |||||
case 4: cmd = 0x40 + alcd->columns; break; | |||||
} | |||||
cmd |= (x - 1); | |||||
// Calculate command | |||||
cmd |= LCD_DDRAMMask; | |||||
// Command out the alcd | |||||
_command (alcd, cmd); | |||||
} | |||||
/* | |||||
* ============================ Public Functions ============================ | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's DB4 pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db4 = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's DB5 pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db5 = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's DB6 pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db6 = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's DB7 pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db7 = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's RS pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.rs = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's EN pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.en = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Link driver's db4 pin function to io struct. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pfun driver's BL pin function | |||||
* \return none | |||||
*/ | |||||
inline void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.bl = pfun; } | |||||
/*! | |||||
* \brief | |||||
* Send an ascii character to alcd. | |||||
* \param alcd pointer to active alcd. | |||||
* \param ch the character to send | |||||
* \return the character send. | |||||
* | |||||
* \note | |||||
* This is the driver's "putchar()" functionality to glue. | |||||
* Tailor this function to redirect stdout to alcd. | |||||
*/ | |||||
int alcd_putchar (alcd_t *alcd, int ch) | |||||
{ | |||||
alcd->status = DRV_BUSY; | |||||
// LCD Character dispatcher | |||||
switch (ch) { | |||||
case 0: | |||||
// don't send null termination to device | |||||
break; | |||||
case '\n': | |||||
_inc_y (alcd); | |||||
//break; This "no break" is intentional | |||||
case '\r': | |||||
_set_cursor (alcd, 1, alcd->c.y); | |||||
break; | |||||
case '\v': | |||||
alcd->c.x = alcd->c.y = 1; | |||||
_command (alcd, LCD_RETHOME); | |||||
jf_delay_us(2000); | |||||
break; | |||||
case '\f': | |||||
//alcd->c.x = alcd->c.y = 1; | |||||
_set_cursor (alcd, 1, 1); | |||||
//_command (alcd, LCD_CLRSCR); | |||||
//jf_delay_us(5000); | |||||
//_command (alcd, LCD_RETHOME); | |||||
//_set_cursor (alcd, alcd->c.x, alcd->c.y); | |||||
jf_delay_us(2000); | |||||
break; | |||||
case '\b': | |||||
if (_dec_x (alcd)) _dec_y (alcd); | |||||
_set_cursor (alcd, alcd->c.x, alcd->c.y); | |||||
_character (alcd, ' '); | |||||
_set_cursor (alcd, alcd->c.x, alcd->c.y); | |||||
break; | |||||
default: | |||||
_character (alcd, ch); | |||||
// Increase cursor and loop inside the same line | |||||
if (_inc_x (alcd)) _set_cursor (alcd, alcd->c.x, alcd->c.y); | |||||
break; | |||||
} | |||||
// Restore status | |||||
alcd->status = DRV_READY; | |||||
//ANSI C (C99) compatible mode | |||||
return ch; | |||||
} | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Set the number of lines for the attached lcd display | |||||
* \param alcd pointer to active alcd. | |||||
* \param lines The number of lines (usually 2 or 4) | |||||
* \return None. | |||||
*/ | |||||
void alcd_set_lines (alcd_t *alcd, int lines) { | |||||
alcd->lines = lines; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Set the number of columns for the attached lcd display | |||||
* \param alcd pointer to active alcd. | |||||
* \param lines The number of columns (usually 16 or 20) | |||||
* \return None. | |||||
*/ | |||||
void alcd_set_columns (alcd_t *alcd, int columns) { | |||||
alcd->columns = columns; | |||||
} | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* De-initialize the alcd. | |||||
* \param alcd pointer to active alcd. | |||||
* \return none | |||||
*/ | |||||
void alcd_deinit (alcd_t *alcd) | |||||
{ | |||||
memset ((void*)alcd, 0, sizeof (alcd_t)); | |||||
/*!< | |||||
* This leaves the status DRV_NOINIT | |||||
*/ | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Initialize the alcd. | |||||
* \param alcd pointer to active alcd. | |||||
* \return Zero on success, non zero on error | |||||
*/ | |||||
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs) | |||||
{ | |||||
#define _lcd_assert(_x) if (!_x) return alcd->status = DRV_ERROR; | |||||
drv_status_en st = jf_probe (); | |||||
if (st == DRV_NODEV || st == DRV_BUSY) | |||||
return alcd->status = DRV_ERROR; | |||||
_lcd_assert (alcd->io.db4); | |||||
_lcd_assert (alcd->io.db5); | |||||
_lcd_assert (alcd->io.db6); | |||||
_lcd_assert (alcd->io.db7); | |||||
_lcd_assert (alcd->io.rs); | |||||
_lcd_assert (alcd->io.en); | |||||
//_lcd_assert (alcd->io.bl); | |||||
/* | |||||
* We are here, so all its OK. We can (re)initialize alcd. | |||||
*/ | |||||
alcd->status = DRV_NOINIT; | |||||
alcd->c.x = alcd->c.y = 1; | |||||
alcd->io.en (0); | |||||
alcd->io.rs (0); | |||||
jf_delay_us (100000); | |||||
//Pre-Init phase 8bit at this point | |||||
_set_bus (alcd, 0x3); | |||||
jf_delay_us(50000); | |||||
_set_bus (alcd, 0x3); | |||||
jf_delay_us(5000); | |||||
_set_bus (alcd, 0x3); | |||||
jf_delay_us(5000); | |||||
_set_bus (alcd, 0x2); //4bit selection | |||||
jf_delay_us(10000); | |||||
_command (alcd, fs); //4bit selection and Function Set | |||||
jf_delay_us(5000); | |||||
_command (alcd, LCD_DISP_OFF); //Display Off Control 4bit for now on | |||||
jf_delay_us(5000); | |||||
_command (alcd, LCD_CLRSCR); //Clear Display | |||||
jf_delay_us(5000); | |||||
_command (alcd, LCD_ENTRYMODE); //Entry Mode Set | |||||
jf_delay_us(5000); | |||||
_command (alcd, LCD_RETHOME); | |||||
jf_delay_us(10000); | |||||
_command (alcd, LCD_DISP_ON); | |||||
jf_delay_us(5000); | |||||
//alcd_backlight (alcd, 1); | |||||
return alcd->status = DRV_READY; | |||||
#undef _lcd_assert | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Enables and disables the lcd backlight. | |||||
* \param alcd pointer to active alcd. | |||||
* \param on | |||||
* \arg 0 disable the backlight | |||||
* \arg 1 enable the backlight | |||||
* \return none | |||||
*/ | |||||
void alcd_backlight (alcd_t *alcd, uint8_t on) { | |||||
if (alcd->io.bl) | |||||
alcd->io.bl ((on)?1:0); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Enables and disables the entire lcd (+backlight). | |||||
* \param alcd pointer to active alcd. | |||||
* \param on | |||||
* \arg 0 disable the backlight | |||||
* \arg 1 enable the backlight | |||||
* \return none | |||||
*/ | |||||
void alcd_enable (alcd_t *alcd, uint8_t on) | |||||
{ | |||||
if (on) { | |||||
_command (alcd, LCD_DISP_ON); | |||||
alcd_backlight (alcd, 1); | |||||
} else { | |||||
_command (alcd, LCD_DISP_OFF); | |||||
alcd_backlight (alcd, 0); | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Clears screen and returns cursor at home position (1,1). | |||||
* \param alcd pointer to active alcd. | |||||
* \return none | |||||
*/ | |||||
void alcd_cls (alcd_t *alcd) | |||||
{ | |||||
_command(alcd, LCD_CLRSCR); | |||||
jf_delay_us(2000); | |||||
_command (alcd, LCD_RETHOME); | |||||
jf_delay_us(2000); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Shift alcd left or right for a \a pos characters. | |||||
* \param alcd pointer to active alcd. | |||||
* \param pos The number of position to shift. | |||||
* A positive number shifts lcd data to left, so screen shows the data in the right. | |||||
* A negative number shifts lcd data to right, so screen shows the data in the left. | |||||
* \return none | |||||
*/ | |||||
void alcd_shift (alcd_t *alcd, int pos) | |||||
{ | |||||
uint8_t i, cmd = LCD_SHIFT_LEFT; | |||||
if (pos<0) { | |||||
pos = -pos; | |||||
cmd = LCD_SHIFT_RIGHT; | |||||
} | |||||
for (i=0 ; i<pos ; ++i) { | |||||
_command (alcd, cmd); | |||||
jf_delay_us(100); | |||||
} | |||||
} | |||||
// Allows us to fill the first 8 CGRAM locations | |||||
// with custom characters | |||||
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[]) | |||||
{ | |||||
location &= 0x7; // we only have 8 locations 0-7 | |||||
_command (alcd, LCD_SETCGRAMADDR | (location << 3)); | |||||
for (int i=0; i<8; i++) { | |||||
_character (alcd, charmap[i]); | |||||
} | |||||
} | |||||
@@ -0,0 +1,189 @@ | |||||
/*! | |||||
* \file alcd.c | |||||
* \brief | |||||
* A target independent Alpharithmetic LCD driver | |||||
* | |||||
* Copyright (C) 2014 Christos Choutouridis (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef __alcd_h__ | |||||
#define __alcd_h__ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#include "jiffies.h" | |||||
#include "driver_types.h" | |||||
#include <stdint.h> | |||||
#include <string.h> | |||||
#include <ctype.h> | |||||
#include <time.h> | |||||
/* | |||||
* General Defines | |||||
*/ | |||||
#define ALCD_CLOCK (CLOCK) | |||||
/*! | |||||
* ---------------------------------------------------- | |||||
* Hitachi HD44780 - Samsung KS0066U | |||||
* ---------------------------------------------------- | |||||
* | |||||
* | |||||
* Entry Mode Set -----> 0 0 0 0 0 1 I/D S | |||||
* ---------------------------------------------------- | |||||
* I/D = 1 -->Inciment Curs I/D = 0 Decriment | |||||
* S = 1 -->Display shift S = 0 Not | |||||
* | |||||
* | |||||
* DispOnOffControll --> 0 0 0 0 1 D C B | |||||
* ------------------------------------------------- | |||||
* D = Display On | |||||
* C = Cursor On | |||||
* B = Blinking On | |||||
* | |||||
* | |||||
* Cursor/Display Shift --> 0 0 0 1 S/C R/L x x | |||||
* --------------------------------------------------- | |||||
* S/C = 1 -->Display Shift S/C = 0 -->Cursor Shift | |||||
* R/L = 1 -->Shift Right R/L = 0 -->Shift left | |||||
* | |||||
* | |||||
* FunctionSet ------> 0 0 1 DL N F x x | |||||
* --------------------------------------------------- | |||||
* DL = 1 -->8bit DL = 0 -->4bit | |||||
* N = 1 -->2 lines N = 0 -->1 line | |||||
* F = 1 -->5x10 dots F = 0 -->5x8 dots | |||||
* | |||||
*/ | |||||
//#define LCD_LINES (4) | |||||
//#define LCD_ROWS (16) | |||||
#define LCD_CLRSCR (0x01) /*!< Clear Srean Command Number */ | |||||
#define LCD_RETHOME (0x02) /*!< Cursor home Un-Shift display DDRam as is */ | |||||
#define LCD_ENTRYMODE (0x06) /*!< Inc Cursor, Don't shift display */ | |||||
#define LCD_DISP_ON (0x0C) /*!< No Cursos and Blink */ | |||||
#define LCD_DISP_OFF (0x08) | |||||
#define LCD_CUR_DISP (0x14) /*!< Cursor shift right */ | |||||
#define LCD_FUNSET_2L8 (0x28) /*!< 4bit, 2lines, 5x8 dots */ | |||||
#define LCD_FUNSET_1L8 (0x20) /*!< 4bit, 1lines, 5x8 dots */ | |||||
#define LCD_FUNSET_1L10 (0x24) /*!< 4bit, 1lines, 5x10 dots */ | |||||
#define LCD_SETCGRAMADDR (0x40) | |||||
#define LCD_DDRAMMask (0x80) /*!< DDRAM ------------> 1 ADD[7..0] */ | |||||
#define LCD_BFMask (0x80) /*!< IR ------------> BF AC[6..0] */ | |||||
#define LCD_ACMask (0x7f) /*!< ____________________________| */ | |||||
#define LCD_SHIFT_RIGHT (0x1C) | |||||
#define LCD_SHIFT_LEFT (0x18) | |||||
typedef enum { | |||||
ALCD_1Line_5x8 = LCD_FUNSET_1L8, | |||||
ALCD_1Line_5x10 = LCD_FUNSET_1L10, | |||||
ALCD_2Lines_5x8 = LCD_FUNSET_2L8 | |||||
} alcd_funset_en; | |||||
/*! | |||||
* Alpharithmetic LCD Cursor | |||||
*/ | |||||
typedef volatile struct | |||||
{ | |||||
uint8_t x; | |||||
uint8_t y; | |||||
}alcd_cursor_t; | |||||
/*! | |||||
* Alpharithmetic LCD Pin assignements. | |||||
* Each one can be called xx.DB4(1); or xx.DB4(0); in order to set | |||||
* or clear the corresponding pin. | |||||
* | |||||
* \note These pointers MUST to be assigned from main application. | |||||
*/ | |||||
typedef volatile struct | |||||
{ | |||||
//drv_pinout_ft db0; | |||||
//drv_pinout_ft db1; | |||||
//drv_pinout_ft db2; | |||||
//drv_pinout_ft db3; | |||||
drv_pinout_ft db4; /*!< Pointer for DB4 pin */ | |||||
drv_pinout_ft db5; /*!< Pointer for DB5 pin */ | |||||
drv_pinout_ft db6; /*!< Pointer for DB6 pin */ | |||||
drv_pinout_ft db7; /*!< Pointer for DB7 pin */ | |||||
drv_pinout_ft rs; /*!< Pointer for RS pin */ | |||||
drv_pinout_ft en; /*!< Pointer for EN pin */ | |||||
drv_pinout_ft bl; /*!< Pointer for Back Light pin*/ | |||||
}alcd_io_t; | |||||
/*! | |||||
* Alpharithmetic LCD Public Data struct | |||||
*/ | |||||
typedef volatile struct | |||||
{ | |||||
alcd_io_t io; //!< Link to IO struct | |||||
alcd_cursor_t c; //!< Link to Cursor struct | |||||
uint8_t lines; //!< The lines of attached lcd | |||||
uint8_t columns; //!< The columns of attached lcd | |||||
//uint8_t bus; //!< Bus length, 4 or 8 bit | |||||
drv_status_en status; //!< alcd driver status | |||||
}alcd_t; | |||||
/* | |||||
* ============= PUBLIC ALCD API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun); | |||||
void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun); | |||||
int alcd_putchar (alcd_t *alcd, int ch); | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
void alcd_set_lines (alcd_t *alcd, int lines); | |||||
void alcd_set_columns (alcd_t *alcd, int columns); | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
void alcd_deinit (alcd_t *alcd); /*!< For compatibility */ | |||||
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs); /*!< For compatibility */ | |||||
void alcd_backlight (alcd_t *alcd, uint8_t on); /*!< For compatibility */ | |||||
void alcd_enable (alcd_t *alcd, uint8_t on); /*!< For compatibility */ | |||||
void alcd_cls (alcd_t *alcd); /*!< For compatibility */ | |||||
void alcd_shift (alcd_t *alcd, int pos); /*!< For compatibility */ | |||||
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[]); | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif //#ifndef __alcd_h__ |
@@ -0,0 +1,223 @@ | |||||
/*! | |||||
* \file deque08.c | |||||
* \brief | |||||
* This file provides double ended queue capability based on a ring buffer | |||||
* | |||||
* Copyright (C) 2014 Houtouridis Christos <houtouridis.ch@gmail.com> | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#include "deque08.h" | |||||
/* | |||||
* ============= Private Queue API ============= | |||||
*/ | |||||
static iterator_t _preInc(deque08_t *q, iterator_t* it) { | |||||
return (++*it >= q->capacity) ? *it=0 : *it; | |||||
} | |||||
static iterator_t _preDec(deque08_t *q, iterator_t* it) { | |||||
return (--*it < 0) ? *it=q->capacity-1 : *it; | |||||
} | |||||
static iterator_t _postInc(deque08_t *q, iterator_t* it) { | |||||
iterator_t ret = *it; | |||||
if (++*it >= q->capacity) *it=0; | |||||
return ret; | |||||
} | |||||
static iterator_t _postDec(deque08_t *q, iterator_t* it) { | |||||
iterator_t ret = *it; | |||||
if (--*it < 0) *it=q->capacity-1; | |||||
return ret; | |||||
} | |||||
/* | |||||
* ============= Public Queue API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
void deque08_link_buffer (deque08_t *q, byte_t* buf) { | |||||
q->m = buf; | |||||
} | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
inline void deque08_set_capacity (deque08_t *q, size_t capacity) { | |||||
q->capacity = capacity; | |||||
} | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Check if deque is full | |||||
* \param q Which deque to check | |||||
* \return | |||||
* \arg 0 Not full | |||||
* \arg 1 Full | |||||
*/ | |||||
int deque08_is_full (deque08_t *q) { | |||||
return (q->items == q->capacity) ? 1:0; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Check if deque is empty | |||||
* \param q Which deque to check | |||||
* \return | |||||
* \arg 0 Not empty | |||||
* \arg 1 Empty | |||||
*/ | |||||
int deque08_is_empty (deque08_t *q) { | |||||
return (q->items) ? 0:1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the number of items on deque | |||||
* \param q Which deque to check | |||||
*/ | |||||
int deque08_size (deque08_t *q) { | |||||
return q->items; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Discard all items in deque | |||||
* \param q Which deque to check | |||||
*/ | |||||
void deque08_flush (deque08_t *q) { | |||||
deque08_init(q); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Initialize the queue | |||||
* \param queue Which queue to init | |||||
*/ | |||||
void deque08_init (deque08_t *q) { | |||||
q->f = 0; | |||||
q->r = -1; | |||||
q->items =0; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function push a byte in front of deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b byte to push | |||||
* \return | |||||
* \arg 0 Full queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_push_front (deque08_t *q, byte_t b) { | |||||
if (deque08_is_full (q) == 1) //full queue | |||||
return 0; | |||||
q->m [_preDec (q, &q->f)] = b; | |||||
++q->items; | |||||
return 1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function pops a byte from the front of the deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b Pointer to byte to return | |||||
* \return | |||||
* \arg 0 Empty queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_pop_front (deque08_t *q, byte_t *b) { | |||||
if (deque08_is_empty (q) == 1) //empty queue | |||||
return 0; | |||||
*b = q->m [_postInc (q, &q->f)]; | |||||
--q->items; | |||||
return 1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function push a byte in the back of deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b byte to push | |||||
* \return | |||||
* \arg 0 Full queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_push_back (deque08_t *q, byte_t b) { | |||||
if (deque08_is_full (q) == 1) //full queue | |||||
return 0; | |||||
q->m [_preInc (q, &q->r)] = b; | |||||
++q->items; | |||||
return 1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function pops a byte from the back of the deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b Pointer to byte to return | |||||
* \return | |||||
* \arg 0 Empty queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_pop_back (deque08_t *q, byte_t *b) { | |||||
if (deque08_is_empty (q) == 1) //empty queue | |||||
return 0; | |||||
*b = q->m [_postDec (q, &q->r)]; | |||||
--q->items; | |||||
return 1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function gives the last item in the back of deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b Pointer to byte to return | |||||
* \return | |||||
* \arg 0 Empty queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_back (deque08_t *q, byte_t *b) { | |||||
if (deque08_is_empty (q) == 1) //empty queue | |||||
return 0; | |||||
*b = q->m [q->r]; | |||||
return 1; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* This function gives the first item in the front of deque. | |||||
* \param q Pointer to deque to use | |||||
* \param b Pointer to byte to return | |||||
* \return | |||||
* \arg 0 Empty queue | |||||
* \arg 1 Done | |||||
*/ | |||||
int deque08_front (deque08_t *q, byte_t *b) { | |||||
if (deque08_is_empty (q) == 1) //empty queue | |||||
return 0; | |||||
*b = q->m [q->f]; | |||||
return 1; | |||||
} |
@@ -0,0 +1,77 @@ | |||||
/*! | |||||
* \file deque08.h | |||||
* \brief | |||||
* This file provides double ended queue capability based on a ring buffer | |||||
* | |||||
* Copyright (C) 2014 Houtouridis Christos <houtouridis.ch@gmail.com> | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef __deque08_h__ | |||||
#define __deque08_h__ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#include "driver_types.h" | |||||
#include <string.h> | |||||
typedef struct { | |||||
byte_t *m; /*!< pointer to queue's buffer */ | |||||
iterator_t capacity; /*!< queue's max item capacity */ | |||||
iterator_t items; /*!< current item count */ | |||||
iterator_t f, r; /*!< queue iterators */ | |||||
}deque08_t; | |||||
/* | |||||
* ============= PUBLIC EE API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
void deque08_link_buffer (deque08_t *q, byte_t* buf); | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
void deque08_set_capacity (deque08_t *q, size_t capacity); | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
int deque08_is_full (deque08_t *q); | |||||
int deque08_is_empty (deque08_t *q); | |||||
int deque08_size (deque08_t *q); | |||||
void deque08_flush (deque08_t *q); | |||||
void deque08_init (deque08_t *q); | |||||
int deque08_push_front (deque08_t *q, byte_t b); | |||||
int deque08_pop_front (deque08_t *q, byte_t *b); | |||||
int deque08_push_back (deque08_t *q, byte_t b); | |||||
int deque08_pop_back (deque08_t *q, byte_t *b); | |||||
int deque08_back (deque08_t *q, byte_t *b); | |||||
int deque08_front (deque08_t *q, byte_t *b); | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif //#ifndef __deque08_h__ |
@@ -0,0 +1,76 @@ | |||||
/*! | |||||
* \file driver_types.h | |||||
* | |||||
* Copyright (C) 2020 Choutouridis Christos <cchoutou@ece.auth.gr> | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef DRIVERS_DRIVER_TYPES_H_ | |||||
#define DRIVERS_DRIVER_TYPES_H_ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#include <stdint.h> | |||||
typedef uint8_t byte_t; /*!< 8 bits wide */ | |||||
typedef uint16_t word_t; /*!< 16 bits wide */ | |||||
typedef uint32_t dword_t; /*!< 32 bits wide */ | |||||
typedef int32_t iterator_t; /*!< general iterator type */ | |||||
/*! | |||||
* This is a driver wide generic driver status type. | |||||
* \note | |||||
* DRV_NOINIT = 0, so after memset to zero called by XXXX_deinit() the | |||||
* module/device will automatically set to NOINIT state. | |||||
*/ | |||||
typedef enum { | |||||
DRV_NODEV=-1, /*!< No device/module */ //!< DRV_NODEV | |||||
DRV_NOINIT=0, /*!< Module/Device exist but no initialized *///!< DRV_NOINIT | |||||
DRV_READY, /*!< Module/Device initialized succesfully */ //!< DRV_READY | |||||
DRV_BUSY, /*!< Module/Device busy */ //!< DRV_BUSY | |||||
//DRV_COMPLETE, /*!< Module/device operation complete status */ | |||||
DRV_ERROR /*!< Module/Device error */ //!< DRV_ERROR | |||||
}drv_status_en; | |||||
typedef enum { | |||||
drv_pin_disable = 0, | |||||
drv_pin_input, | |||||
drv_pin_output | |||||
}drv_pin_dir_en; | |||||
/*! | |||||
* Pin function pointers | |||||
* \note | |||||
* These function pointers do not correspond to pin levels. | |||||
* They correspond to the enable/disable functionality of that pin. | |||||
*/ | |||||
//! @{ | |||||
typedef uint8_t (*drv_pinin_ft) (void); | |||||
typedef void (*drv_pinout_ft) (uint8_t); | |||||
typedef uint8_t (*drv_pinio_ft) (uint8_t); | |||||
typedef void (*drv_pindir_ft) (drv_pin_dir_en); | |||||
//! @} | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* DRIVERS_DRIVER_TYPES_H_ */ |
@@ -0,0 +1,209 @@ | |||||
/*! | |||||
* \file hal.c | |||||
* | |||||
* Copyright (C) 2020 Choutouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#include "hal.h" | |||||
/* | |||||
* Public data types / classes | |||||
*/ | |||||
alcd_t alcd; | |||||
ow_uart_t ow; | |||||
proximity_t prox; | |||||
/*! | |||||
* Initialize all hardware | |||||
* @return | |||||
*/ | |||||
int hal_hw_init (void) { | |||||
// Init base board | |||||
NUCLEO_Init(1000); | |||||
SHIELD_Init (); | |||||
// Start Jiffy functionality | |||||
jf_link_setfreq (JF_setfreq); | |||||
jf_link_value ((jiffy_t*)&JF_TIM_VALUE); | |||||
jf_init (JF_TIM_CLOCK_FREQ, 1000); | |||||
return 0; | |||||
} | |||||
/* | |||||
* ========== LCD =========== | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Initialize the lcd data. Not the LCD module | |||||
*/ | |||||
void lcd_init (void) { | |||||
alcd_link_db4 (&alcd, SHIELD_LCD_DB4); | |||||
alcd_link_db5 (&alcd, SHIELD_LCD_DB5); | |||||
alcd_link_db6 (&alcd, SHIELD_LCD_DB6); | |||||
alcd_link_db7 (&alcd, SHIELD_LCD_DB7); | |||||
alcd_link_rs (&alcd, SHIELD_LCD_RS); | |||||
alcd_link_en (&alcd, SHIELD_LCD_EN); | |||||
alcd_link_bl (&alcd, SHIELD_LCD_BL); | |||||
alcd_set_lines (&alcd, 2); | |||||
alcd_set_columns (&alcd, 16); | |||||
alcd_init (&alcd, (alcd_funset_en)LCD_FUNSET_2L8); | |||||
} | |||||
__INLINE void lcd_enable (uint8_t en) { | |||||
alcd_enable(&alcd, en); | |||||
} | |||||
__INLINE int lcd_putchar (char c) { | |||||
return alcd_putchar(&alcd, c); | |||||
} | |||||
int lcd_puts (const char *s) { | |||||
int i =0; | |||||
while (alcd_putchar(&alcd, *s++)) | |||||
++i; | |||||
return i; | |||||
} | |||||
/* | |||||
* ========== Led interface ========== | |||||
*/ | |||||
__INLINE void led_red (uint8_t en) { LED_RED (en); } | |||||
__INLINE void led_green (uint8_t en) { LED_GREEN (en); } | |||||
/* | |||||
* ========= Relay =========== | |||||
*/ | |||||
void relay (uint8_t on) { | |||||
switch (on) { | |||||
case 0: | |||||
SHIELD_BR1(1); | |||||
HAL_Delay(100); | |||||
SHIELD_BR1(0); | |||||
break; | |||||
default: | |||||
SHIELD_BR2(1); | |||||
HAL_Delay(100); | |||||
SHIELD_BR2(0); | |||||
break; | |||||
} | |||||
} | |||||
/* | |||||
* ========= Temperature =========== | |||||
*/ | |||||
uint8_t ds18b20_rom[8]; | |||||
uint8_t zero_rom[8] = {0}; | |||||
int temp_init (uint8_t resolution) { | |||||
if (!IS_TEMP_RESOLUTION(resolution)) | |||||
return 1; | |||||
ow_uart_link_rw (&ow, (ow_uart_rw_ft)SHIELD_1W_RW); | |||||
ow_uart_link_br (&ow, (ow_uart_br_ft)SHIELD_1W_UART_BR); | |||||
ow_uart_set_timing (&ow, OW_UART_T_STANDARD); | |||||
ow_uart_init (&ow); | |||||
ow_uart_search(&ow, ds18b20_rom); | |||||
if (!memcmp ((const void*)ds18b20_rom, (const void*)zero_rom, 8)) | |||||
return 1; | |||||
// set resolution to 9-bit | |||||
ow_uart_reset(&ow); | |||||
ow_uart_tx (&ow, SKIPROM); // Skip rom | |||||
ow_uart_tx (&ow, WRITESCRATCH); // write scratchpad | |||||
ow_uart_tx (&ow, (byte_t)127); // Th | |||||
ow_uart_tx (&ow, (byte_t)-128); // Tl | |||||
ow_uart_tx (&ow, resolution); // Configuration 9 bit | |||||
HAL_Delay(100); | |||||
return 0; | |||||
} | |||||
float temp_read (void) { | |||||
uint8_t t[2]; | |||||
ow_uart_reset(&ow); | |||||
ow_uart_tx (&ow, SKIPROM); // Skip rom | |||||
ow_uart_tx (&ow, STARTCONV); // convert temperature | |||||
while (ow_uart_rx(&ow) == 0) // Wait for slave to free the bus | |||||
; | |||||
//HAL_Delay (100); | |||||
ow_uart_reset(&ow); | |||||
ow_uart_tx (&ow, SKIPROM); // Skip rom | |||||
ow_uart_tx (&ow, READSCRATCH); // read scratchpad | |||||
t[0] = ow_uart_rx(&ow); // LSB | |||||
t[1] = ow_uart_rx(&ow); // MSB | |||||
ow_uart_reset(&ow); | |||||
t[1] <<= 4; | |||||
t[1] |= (t[0] >> 4); | |||||
t[0] &= 0x0F; | |||||
return t[1] + t[0]/16.0; | |||||
} | |||||
/* | |||||
* ========= Proximity =========== | |||||
*/ | |||||
void proximity_init (proximity_t* p){ | |||||
for (int i =0 ; i<PROX_READINGS ; ++i) | |||||
proximity(p); | |||||
} | |||||
float_t proximity (proximity_t* p){ | |||||
float_t ret; | |||||
clock_t t1, t2, mark; | |||||
SHIELD_TRIG(1); // send pulse and mark cycles | |||||
jf_delay_us(10); | |||||
SHIELD_TRIG(0); | |||||
// wait for response with timeout | |||||
mark = clock(); | |||||
do { | |||||
t1 = CYCLE_Get(); | |||||
if (clock() - mark >= PROX_TIME_MAX) | |||||
return -1; | |||||
} while (!SHIELD_ECHO()); | |||||
mark = clock(); | |||||
do { | |||||
t2 = CYCLE_Get(); | |||||
if (clock() - mark >= PROX_TIME_MAX) | |||||
return -1; | |||||
} while (SHIELD_ECHO()); | |||||
SystemCoreClockUpdate(); | |||||
uint32_t c_usec = SystemCoreClock / 1000000; | |||||
// Load value | |||||
p->readings[p->iter++] = (c_usec) ? ((t2 - t1)/c_usec) / 58.2 : PROX_MAX_DISTANSE; | |||||
p->iter %= PROX_READINGS; | |||||
// Return filtered distance | |||||
ret =0; | |||||
for (int i=0 ; i<PROX_READINGS ; ++i) | |||||
ret += p->readings[i]; | |||||
return ret/PROX_READINGS; | |||||
} | |||||
@@ -0,0 +1,109 @@ | |||||
/*! | |||||
* \file hal.h | |||||
* | |||||
* Copyright (C) 2020 Choutouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef DRIVERS_HAL_H_ | |||||
#define DRIVERS_HAL_H_ | |||||
#include <thermostat_shield.h> | |||||
#include <alcd.h> | |||||
#include <jiffies.h> | |||||
#include <onewire_uart.h> | |||||
#include <deque08.h> | |||||
#include <thermostat.h> | |||||
#include <stdio.h> | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
int hal_hw_init (void); | |||||
/* | |||||
* ========== LCD =========== | |||||
*/ | |||||
void lcd_init (void); | |||||
void lcd_enable (uint8_t en) ; | |||||
int lcd_putchar (char c); | |||||
int lcd_puts (const char *s); | |||||
/* | |||||
* ========== Led interface ========== | |||||
*/ | |||||
void led_red (uint8_t en); | |||||
void led_green (uint8_t en); | |||||
/* | |||||
* ========= Relay =========== | |||||
*/ | |||||
void relay(uint8_t on); | |||||
/* | |||||
* ========= Temperature =========== | |||||
*/ | |||||
// OneWire commands | |||||
#define SKIPROM 0xCC // Skip ROM matching transition | |||||
#define STARTCONV 0x44 // Tells device to take a temperature reading and put it on the scratchpad | |||||
#define COPYSCRATCH 0x48 // Copy EEPROM | |||||
#define READSCRATCH 0xBE // Read EEPROM | |||||
#define WRITESCRATCH 0x4E // Write to EEPROM | |||||
#define RECALLSCRATCH 0xB8 // Reload from last known | |||||
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power | |||||
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition | |||||
// Device resolution | |||||
#define TEMP_9_BIT 0x1F // 9 bit | |||||
#define TEMP_10_BIT 0x3F // 10 bit | |||||
#define TEMP_11_BIT 0x5F // 11 bit | |||||
#define TEMP_12_BIT 0x7F // 12 bit | |||||
#define IS_TEMP_RESOLUTION(x) \ | |||||
((x == TEMP_9_BIT) || (x == TEMP_10_BIT) || (x == TEMP_11_BIT) || (x == TEMP_12_BIT)) | |||||
int temp_init (uint8_t resolution); | |||||
float temp_read (void); | |||||
/* | |||||
* ========= Proximity =========== | |||||
*/ | |||||
#define PROX_TIME_MAX 25 // [msec] | |||||
#define PROX_READINGS 7 // How many readings for averaging | |||||
#define PROX_MAX_DISTANSE 450 // [cm] | |||||
typedef struct { | |||||
float_t readings[7]; | |||||
int iter; | |||||
} proximity_t; | |||||
void proximity_init (proximity_t* p); | |||||
float_t proximity (proximity_t* p); | |||||
/* | |||||
* Public data types / classes | |||||
*/ | |||||
extern alcd_t alcd; | |||||
extern ow_uart_t ow; | |||||
extern proximity_t prox; | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* DRIVERS_HAL_H_ */ |
@@ -0,0 +1,367 @@ | |||||
/* | |||||
* \file jiffies.c | |||||
* \brief | |||||
* A target independent jiffy functionality | |||||
* | |||||
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#include "jiffies.h" | |||||
static jf_t _jf; | |||||
#define JF_MAX_TIM_VALUE (0xFFFF) // 16bit counters | |||||
/* | |||||
* ====================== Public functions ====================== | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Connect the Driver's Set frequency function to jiffy struct | |||||
* \note | |||||
* This function get a freq value and returns the timers max jiffy value | |||||
* (usual this refers to timer'sauto reload value). | |||||
*/ | |||||
void jf_link_setfreq (jf_setfreq_pt pfun) { | |||||
_jf.setfreq = (pfun != 0) ? pfun : 0; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Connect the timer's value to jiffy struct | |||||
*/ | |||||
void jf_link_value (jiffy_t* v) { | |||||
_jf.value = (v != 0) ? v : 0; | |||||
} | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* Check jiffy's status | |||||
* \return status | |||||
*/ | |||||
inline drv_status_en jf_probe (void) { | |||||
return _jf.status; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* De-Initialize the jf data and un-connect the functions | |||||
* from the driver | |||||
*/ | |||||
void jf_deinit (void) | |||||
{ | |||||
if (_jf.setfreq) _jf.setfreq (0, 0); | |||||
memset ((void*)&_jf, 0, sizeof (jf_t)); | |||||
_jf.status = DRV_NODEV; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Initialize the jf to a desired jiffy frequency | |||||
* \note | |||||
* This function has no effect if the inner jiffy struct | |||||
* is un-connected to driver. So you have to call | |||||
* \sa jf_connect_setfreq() and \sa jf_connect_value() first. | |||||
* \return The status of the operation | |||||
* \arg DRV_ERROR If the init process fail | |||||
* \arg DRV_NODEV If there is no linked jiffy HW, no setfreq function | |||||
* \arg DRV_READY Success | |||||
*/ | |||||
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies) | |||||
{ | |||||
if (_jf.setfreq) { | |||||
_jf.status = DRV_NOINIT; | |||||
if ( _jf.setfreq (jf_freq, jiffies) ) | |||||
return DRV_ERROR; | |||||
_jf.jiffies = jiffies; | |||||
_jf.freq = jf_freq; | |||||
_jf.jp1ms = jf_per_msec (); | |||||
_jf.jp1us = jf_per_usec (); | |||||
_jf.jp100ns = jf_per_100nsec (); | |||||
return _jf.status = DRV_READY; | |||||
} | |||||
return _jf.status = DRV_NODEV; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the maximum jiffy value. | |||||
*/ | |||||
jiffy_t jf_get_jiffies (void){ | |||||
return _jf.jiffies; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the current jiffy value. | |||||
* \note | |||||
* Usual this function returns the value of a register from a timer peripheral | |||||
* in the MCU. Keep in mind that its value is a moving target! | |||||
*/ | |||||
jiffy_t jf_get_jiffy (void){ | |||||
return *_jf.value; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the systems best approximation for jiffies per msec | |||||
* \return | |||||
* The calculated value or zero if no calculation can apply | |||||
* | |||||
* \note | |||||
* The result tend to differ as the jiffies and freq values decreasing | |||||
*/ | |||||
jiffy_t jf_per_msec (void) | |||||
{ | |||||
jiffy_t jf = (jiffy_t)(_jf.freq / 1000); | |||||
/* 1 | |||||
* 1000Hz = ----- , Its not a magic number | |||||
* 1msec | |||||
*/ | |||||
if (jf <= 1) return 1; | |||||
else return jf; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the systems best approximation for jiffies per usec | |||||
* \return | |||||
* The calculated value or zero if no calculation can apply | |||||
* | |||||
* \note | |||||
* The result tend to differ as the jiffies and freq values decreasing | |||||
*/ | |||||
jiffy_t jf_per_usec (void) | |||||
{ | |||||
jiffy_t jf = (jiffy_t)(_jf.freq / 1000000); | |||||
/* 1 | |||||
* 1000000Hz = ------ , Its not a magic number | |||||
* 1usec | |||||
*/ | |||||
if (jf <= 1) return 1; | |||||
else return jf; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Return the systems best approximation for jiffies per usec | |||||
* \return | |||||
* The calculated value or zero if no calculation can apply | |||||
* | |||||
* \note | |||||
* The result tend to differ as the jiffies and freq values decreasing | |||||
*/ | |||||
jiffy_t jf_per_100nsec (void) | |||||
{ | |||||
jiffy_t jf = (jiffy_t)(_jf.freq / 10000000); | |||||
/* 1 | |||||
* 10000000Hz = ------- , Its not a magic number | |||||
* 100nsec | |||||
*/ | |||||
if (jf <= 1) return 1; | |||||
else return jf; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 1 msec. | |||||
* \param msec Time in msec for delay | |||||
*/ | |||||
void jf_delay_ms (jtime_t msec) | |||||
{ | |||||
jtime_t m, m2, m1 = (jtime_t)*_jf.value; | |||||
msec *= _jf.jp1ms; | |||||
// Eat the time difference from msec value. | |||||
do { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2 - m1; | |||||
msec -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
} while (msec>0); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 1 usec. | |||||
* \param usec Time in usec for delay | |||||
*/ | |||||
void jf_delay_us (jtime_t usec) | |||||
{ | |||||
jtime_t m, m2, m1 = (jtime_t)*_jf.value; | |||||
usec *= _jf.jp1us; | |||||
if ((jtime_t)(*_jf.value) - m1 > usec) // Very small delays may return here. | |||||
return; | |||||
// Eat the time difference from usec value. | |||||
do { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2 - m1; | |||||
usec -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
} while (usec>0); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 100 nsec. | |||||
* \param _100nsec Time in 100nsec for delay | |||||
*/ | |||||
void jf_delay_100ns (jtime_t _100nsec) | |||||
{ | |||||
jtime_t m, m2, m1 = (jtime_t)*_jf.value; | |||||
_100nsec *= _jf.jp100ns; | |||||
if ((jtime_t)(*_jf.value) - m1 > _100nsec) // Very small delays may return here. | |||||
return; | |||||
// Eat the time difference from _100nsec value. | |||||
do { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2 - m1; | |||||
_100nsec -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
} while (_100nsec>0); | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based polling version delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 1 msec. | |||||
* \param msec Time in msec for delay | |||||
* \return The status of ongoing delay | |||||
* \arg 0: Delay time has passed | |||||
* \arg 1: Delay is ongoing, keep calling | |||||
*/ | |||||
int jf_check_msec (jtime_t msec) | |||||
{ | |||||
static jtime_t m1=-1, cnt; | |||||
jtime_t m, m2; | |||||
if (m1 == -1) { | |||||
m1 = *_jf.value; | |||||
cnt = _jf.jp1ms * msec; | |||||
} | |||||
// Eat the time difference from msec value. | |||||
if (cnt>0) { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2-m1; | |||||
cnt -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
return 1; // wait | |||||
} | |||||
else { | |||||
m1 = -1; | |||||
return 0; // do not wait any more | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based polling version delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 1 usec. | |||||
* \param usec Time in usec for delay | |||||
* \return The status of ongoing delay | |||||
* \arg 0: Delay time has passed | |||||
* \arg 1: Delay is ongoing, keep calling | |||||
*/ | |||||
int jf_check_usec (jtime_t usec) | |||||
{ | |||||
static jtime_t m1=-1, cnt; | |||||
jtime_t m, m2; | |||||
if (m1 == -1) { | |||||
m1 = *_jf.value; | |||||
cnt = _jf.jp1us * usec; | |||||
} | |||||
// Eat the time difference from usec value. | |||||
if (cnt>0) { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2-m1; | |||||
cnt -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
return 1; // wait | |||||
} | |||||
else { | |||||
m1 = -1; | |||||
return 0; // do not wait any more | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* A code based polling version delay implementation, using jiffies for timing. | |||||
* This is NOT accurate but it ensures that the time passed is always | |||||
* more than the requested value. | |||||
* The delay values are multiplications of 100 nsec. | |||||
* \param | |||||
* _100nsec Time in 100nsec for delay | |||||
* \return The status of ongoing delay | |||||
* \arg 0: Delay time has passed | |||||
* \arg 1: Delay is ongoing, keep calling | |||||
*/ | |||||
int jf_check_100nsec (jtime_t _100nsec) | |||||
{ | |||||
static jtime_t m1=-1, cnt; | |||||
jtime_t m, m2; | |||||
if (m1 == -1) { | |||||
m1 = *_jf.value; | |||||
cnt = _jf.jp100ns * _100nsec; | |||||
} | |||||
// Eat the time difference from _100nsec value. | |||||
if (cnt>0) { | |||||
m2 = (jtime_t)(*_jf.value); | |||||
m = m2-m1; | |||||
cnt -= (m>=0) ? m : _jf.jiffies + m; | |||||
m1 = m2; | |||||
return 1; // wait | |||||
} | |||||
else { | |||||
m1 = -1; | |||||
return 0; // do not wait any more | |||||
} | |||||
} |
@@ -0,0 +1,108 @@ | |||||
/* | |||||
* \file jiffies.h | |||||
* \brief | |||||
* A target independent jiffy functionality | |||||
* | |||||
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef __jiffies_h__ | |||||
#define __jiffies_h__ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#include <stdint.h> | |||||
#include <string.h> | |||||
#include "driver_types.h" | |||||
typedef uint16_t jiffy_t; //!< Jiffy type 2 byte unsigned integer | |||||
typedef int32_t jtime_t; //!< Jiffy time type for delay functionalities usec/msec | |||||
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //!< Pointer to setfreq function \sa setfreq | |||||
/*! | |||||
* Jiffy inner structure, | |||||
* \info | |||||
* We use jiffies to count small time intervals and usually this is | |||||
* below SysTick Interrupt. So we use an indepentend counter for that. | |||||
* Linux names jiffies the Tick per sec. This is toooo big for us. | |||||
* We name jiffy each tick of the extra timer. | |||||
* The equalivent of linux jiffies is the return value of clock (). | |||||
*/ | |||||
typedef volatile struct { | |||||
jf_setfreq_pt setfreq; /*!< Pointer to driver's timer set freq function */ | |||||
/* | |||||
* \note | |||||
* This function must get an integer value for timer's desired | |||||
* frequency and returns the maximum jiffy value. This usual | |||||
* refers to timer's auto reload value. | |||||
*/ | |||||
jiffy_t *value; /*!< Pointer to timers current value */ | |||||
uint32_t freq; /*!< timer's frequency */ | |||||
jiffy_t jiffies; /*!< jiffies max value (timer's max value) */ | |||||
jiffy_t jp1ms; /*!< Jiffies per 1 msec to use in delay function */ | |||||
jiffy_t jp1us; /*!< Jiffies per 1 usec to use in delay function */ | |||||
jiffy_t jp100ns; /*!< Jiffies per 100 nsec to use in delay function */ | |||||
drv_status_en status; | |||||
}jf_t; | |||||
/* | |||||
* ============= PUBLIC jiffy API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
void jf_link_setfreq (jf_setfreq_pt pfun); | |||||
void jf_link_value (jiffy_t* v); | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
drv_status_en jf_probe (void); | |||||
void jf_deinit (void); | |||||
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies); | |||||
jiffy_t jf_get_jiffies (void); | |||||
jiffy_t jf_get_jiffy (void); | |||||
jiffy_t jf_per_msec (void); | |||||
jiffy_t jf_per_usec (void); | |||||
jiffy_t jf_per_100nsec (void); | |||||
void jf_delay_ms (jtime_t msec); | |||||
void jf_delay_us (jtime_t usec); | |||||
void jf_delay_100ns (jtime_t _100nsec); | |||||
int jf_check_msec (jtime_t msec); | |||||
int jf_check_usec (jtime_t usec); | |||||
int jf_check_100nsec (jtime_t _100nsec); | |||||
/*! | |||||
* \note | |||||
* The Jiffy lib has no jiffy_t target pointer in the API. This means | |||||
* that IT CAN BE ONLY ONE jiffy timer per application. | |||||
*/ | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif //#ifndef __jiffies_h__ |
@@ -0,0 +1,539 @@ | |||||
/*! | |||||
* \file onewire_uart.c | |||||
* \brief | |||||
* A target independent 1-wire implementation using a microprocessor's uart | |||||
* for bit timing | |||||
* | |||||
* Copyright (C) 2015 Choutouridis Christos (http://www.houtouridis.net) | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#include "onewire_uart.h" | |||||
/* | |||||
* ========= Private helper macros =========== | |||||
*/ | |||||
/*! | |||||
* Clear a virtual 64bit unsigned register. | |||||
* \note | |||||
* We use a uint8_t array[8] to represent that kind | |||||
* of data for this module | |||||
* \param _reg Pointer to register location. Usual the name of | |||||
* The array | |||||
*/ | |||||
#define _clear_u64(_reg_) \ | |||||
memset ((void*)(_reg_), 0, 8*sizeof(uint8_t)) | |||||
/*! | |||||
* Read a bit value of a virtual 64bit unsigned register. | |||||
* \note | |||||
* We use a uint8_t array[8] to represent that kind | |||||
* of data for this module | |||||
* \param _reg Pointer to register location. Usual the name of | |||||
* The array | |||||
* \param _bit The bit location we want to read | |||||
*/ | |||||
#define _read_bit_u64(_reg_, _bit_) \ | |||||
(_reg_[(_bit_)/8] & (1<<((_bit_)%8))) ? 1:0 | |||||
/*! | |||||
* Write/modify a bit value from a virtual 64bit unsigned register. | |||||
* \note | |||||
* We use a uint8_t array[8] to represent that kind | |||||
* of data for this module | |||||
* \param _reg Pointer to register location. Usual the name of | |||||
* The array | |||||
* \param _bit The bit location we want to set | |||||
* \param _v The value we want to set | |||||
* \arg 0 Set to zero | |||||
* \arg !0 Set to One | |||||
*/ | |||||
#define _write_bit_u64(_reg_, _bit_, _v_) \ | |||||
do { \ | |||||
if (_v_) _reg_[(_bit_)/8] |= 1 << ((_bit_)%8); \ | |||||
else _reg_[(_bit_)/8] &= ~(1 << ((_bit_)%8)); \ | |||||
} while (0) | |||||
/* | |||||
* ============= Private functions =========== | |||||
*/ | |||||
/* Data manipulation functions */ | |||||
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2); | |||||
/* Set functions */ | |||||
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st); | |||||
/* Bus functions */ | |||||
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b); | |||||
static uint8_t _read_bit (ow_uart_t *ow); | |||||
/*! | |||||
* \brief | |||||
* Compare two 64bit virtual unsigned registers | |||||
* \note | |||||
* We use a uint8_t array[8] to represent that kind | |||||
* of data for this module | |||||
* \param reg1 Pointer to first register location. Usual the name of | |||||
* the array | |||||
* \param reg1 Pointer to 2nd register location. Usual the name of | |||||
* the array | |||||
* \return The comparison result | |||||
* \arg 0 Registers are equal | |||||
* \arg 1 Register 1 is larger than register 2 | |||||
* \arg -1 Register 2 is larger than register 1 | |||||
*/ | |||||
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2) { | |||||
int i; | |||||
for (i=7 ; i>=0 ; --i) { | |||||
if (reg1[i] > reg2[i]) return 1; /* reg1 > reg2 */ | |||||
else if (reg1[i] < reg2[i]) return -1; /* reg1 < reg2 */ | |||||
} | |||||
return 0; /* reg1 equal reg2 */ | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Set UART Baudrate and handle all function calls and data | |||||
* manipulation | |||||
* \param ow Pointer to select 1-Wire structure for the operation. | |||||
* \param st The 1-Wire operational state \sa ow_uart_state_en | |||||
* \return The status of the operation | |||||
* \arg DRV_ERROR Could not set baudrate (callback pointer function error) | |||||
* \arg DRV_READY Success | |||||
*/ | |||||
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st) | |||||
{ | |||||
uint32_t st_br; | |||||
/* Get the desired baudrate */ | |||||
switch (st) { | |||||
case OWS_RESET: st_br = ow->baudrate.reset; break; | |||||
default: | |||||
case OWS_OPER: st_br = ow->baudrate.oper; break; | |||||
} | |||||
if (ow->baudrate.current != st_br) { | |||||
if (ow->io.br (st_br) != DRV_READY) return DRV_ERROR; | |||||
ow->baudrate.current = st_br; | |||||
} | |||||
return DRV_READY; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Send a 1-Wire write bit | |||||
* | |||||
* --- -------------------------------------- | |||||
* Write 1 \ / | |||||
* ---- | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0xFF | |||||
* RX: 0xFF | |||||
* | |||||
* --- ------ | |||||
* Write 0 \ / | |||||
* ------------------------------------- | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0x00 | |||||
* RX: 0x00 | |||||
* | |||||
* \param ow Pointer to select 1-Wire structure for the operation. | |||||
* \param b The bit to send | |||||
* \return Status of the operation | |||||
* \arg 0 Success | |||||
* \arg 1 Fail | |||||
*/ | |||||
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b) | |||||
{ | |||||
uint8_t w; | |||||
uint16_t r; | |||||
/* | |||||
* Make sure we are at the right baudrate | |||||
*/ | |||||
if (_set_baudrate (ow, OWS_OPER) != DRV_READY) | |||||
return 1; | |||||
/* Select frame to send and check the bus by evaluating the return value */ | |||||
w = (b) ? 0xFF : 0x00; | |||||
r = ow->io.rw (w); | |||||
if (r != w) return 1; | |||||
else return 0; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Read a bit from the 1-Wire bus, return it and provide | |||||
* the recovery time. | |||||
* | |||||
* --- - - - - - - - - - - - ------ | |||||
* Read \ / X X X X X X X X X X X X X X X / | |||||
* ---- - - - - - - - - - - - | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* ^ | |||||
* | | |||||
* Master sample | |||||
* | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0xFF | |||||
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] } | |||||
* | |||||
* \return The answer | |||||
* \arg 0 Read 0 | |||||
* \arg 1 Read 1 (This is also returned on transition error). | |||||
*/ | |||||
static uint8_t _read_bit (ow_uart_t *ow) | |||||
{ | |||||
uint16_t r; | |||||
/* | |||||
* Make sure we are at the right baudrate | |||||
*/ | |||||
if (_set_baudrate (ow, OWS_OPER) != DRV_READY) | |||||
return 1; | |||||
/* Send frame for read */ | |||||
r = ow->io.rw (0xFF); | |||||
/* Dispatch answer */ | |||||
if (r < 0xFF) return 0; | |||||
else return 1; | |||||
} | |||||
/* | |||||
* ============= PUBLIC 1-Wire API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
/*! | |||||
* \brief link driver's UART read-write function | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \param tx ow_uart_rx_ft pointer to drivers UART rx function | |||||
*/ | |||||
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft rw) { | |||||
ow->io.rw = (ow_uart_rw_ft)((rw != 0) ? rw : 0); | |||||
} | |||||
/*! | |||||
* \brief link driver's UART baudrate function | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \param tx ow_uart_tx_ft pointer to drivers UART baudrate function | |||||
*/ | |||||
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br) { | |||||
ow->io.br = (ow_uart_br_ft)((br != 0) ? br : 0); | |||||
} | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
/*! | |||||
* \brief set 1-wire timing mode and update baudrate table. | |||||
* If the owt parameter is not a valid ow_uart_timing_en | |||||
* then set timings to OW_STANDTARD. | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \param owt Timing type | |||||
* \arg OWT_STANDARD Use standard timing | |||||
* \arg OWT_OVERDRIVE Use overdrive timing | |||||
*/ | |||||
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt) { | |||||
ow->timing = (_ow_uart_is_timings(owt)) ? owt : OW_UART_T_STANDARD; | |||||
switch (owt) { | |||||
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break; | |||||
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break; | |||||
} | |||||
} | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
/*! | |||||
* \brief | |||||
* De-Initialize the 1-Wire interface and leave bus pin in input state | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \return none | |||||
*/ | |||||
void ow_uart_deinit (ow_uart_t *ow) | |||||
{ | |||||
// Clear data | |||||
memset ((void*)ow, 0, sizeof (ow_uart_t)); | |||||
/*!< | |||||
* This leaves the status = DRV_NOINIT | |||||
*/ | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Initialize the 1-Wire interface and leave bus high | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \return The driver status after init. | |||||
* \arg DRV_READY | |||||
* \arg DRV_ERROR | |||||
*/ | |||||
drv_status_en ow_uart_init (ow_uart_t *ow) | |||||
{ | |||||
// Check requirements | |||||
if (!ow->io.rw) return ow->status = DRV_ERROR; | |||||
if (!ow->io.br) return ow->status = DRV_ERROR; | |||||
// Init the bus | |||||
ow->status = DRV_BUSY; | |||||
if ( _ow_uart_is_timings(ow->timing) != 1) { | |||||
ow->timing = OW_UART_T_STANDARD; | |||||
_ow_baudrate_standard (ow->baudrate); | |||||
} | |||||
switch (ow->timing) { | |||||
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break; | |||||
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break; | |||||
} | |||||
if (_set_baudrate (ow, OWS_RESET) != DRV_READY) | |||||
return ow->status = DRV_ERROR; | |||||
return ow->status = DRV_READY; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Generate a 1-wire reset | |||||
* | |||||
* --- ---- - - - ------- | |||||
* Reset \ / \ X X X / | |||||
* -------------------- - - - - | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ---------- 1024/174 usec -------------> | |||||
* | |||||
* 8 bits, no parity, 1 stop | |||||
* Standard: Overdrive : | |||||
* BR: 9600, BR: 57600 | |||||
* TX: 0xF0, TX: 0xF8 | |||||
* RX: 0xF0 not present RX: 0xF8 not present | |||||
* less if present less if present | |||||
* | |||||
* \note Does not handle alarm presence from DS2404/DS1994 | |||||
* \param None | |||||
* \return The status of the operation | |||||
* \arg DRV_ERROR Error, callback baudrate error or bus error | |||||
* \arg DRV_NODEV If no presence detect was found | |||||
* \arg DRV_READY Otherwise | |||||
*/ | |||||
drv_status_en ow_uart_reset (ow_uart_t *ow) | |||||
{ | |||||
uint8_t w; | |||||
uint16_t r; | |||||
/* | |||||
* Make sure we are at the write baudrate | |||||
*/ | |||||
if (_set_baudrate (ow, OWS_RESET) != DRV_READY) | |||||
return DRV_ERROR; | |||||
/* Select frame to send */ | |||||
w = (ow->timing == OW_UART_T_OVERDRIVE) ? 0xF8 : 0xF0; | |||||
r = ow->io.rw (w); | |||||
r = ow->io.rw (w); // Send it twice to make sure | |||||
if (w>r) return DRV_READY; | |||||
else if (w==r) return DRV_NODEV; | |||||
else return DRV_ERROR; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Read a byte from 1-Wire bus | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \return The byte received. | |||||
*/ | |||||
uint8_t ow_uart_rx (ow_uart_t *ow) | |||||
{ | |||||
uint8_t i; | |||||
byte_t byte; | |||||
for (i=8, byte=0 ; i>0 ; --i) { | |||||
byte >>= 1; /* shift bits to right as LSB comes first */ | |||||
if (_read_bit (ow) != 0) byte |= 0x80; /* Mask bit to MSB */ | |||||
} | |||||
return byte; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Write a byte to 1-Wire bus | |||||
* \param ow pointer to select 1-Wire structure for the operation. | |||||
* \param b: The byte to write | |||||
* \return none | |||||
*/ | |||||
void ow_uart_tx (ow_uart_t *ow, byte_t byte) | |||||
{ | |||||
uint8_t i; | |||||
for (i=8 ; i>0 ; --i) { | |||||
_write_bit (ow, byte & 0x01); /* Send LSB */ | |||||
byte >>= 1; /* shift bits to right */ | |||||
} | |||||
} | |||||
/*! | |||||
* \brief | |||||
* Write a byte to 1-Wire bus and read the response | |||||
* \param ow Pointer to select 1-Wire structure for the operation. | |||||
* \param byte The byte to write | |||||
* \return The byte received. | |||||
*/ | |||||
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte) | |||||
{ | |||||
uint8_t i; | |||||
byte_t ret; | |||||
for (i=8, ret=0 ; i>0 ; --i) { | |||||
ret >>= 1; /* shift read bits to right as LSB comes first */ | |||||
if ((byte & 0x01) != 0) ret |= (_read_bit (ow) != 0) ? 0x80 : 0x0; | |||||
else _write_bit (ow, 0); | |||||
byte >>= 1; /* shift bits to right */ | |||||
/*!< | |||||
* If the bit is 1 we use the read sequence, as it has the same | |||||
* waveform with write-1 and we get the slave response | |||||
* If the bit is 0, we can not read the slave response so we just write-0 | |||||
*/ | |||||
} | |||||
return byte; | |||||
} | |||||
/*! | |||||
* \brief | |||||
* 1-Wire search algorithm based on maxim-ic application note 187 | |||||
* | |||||
* \param ow Pointer to select 1-Wire structure for the operation. | |||||
* \param romid Pointer to romid to return. If the search is success | |||||
* this points to and 64bit long array with ROM ID | |||||
* \return The status of the search | |||||
* \arg DRV_NODEV (-1) Search was failed, No device found | |||||
* \arg DRV_READY (1) Search is complete, all ROM IDs was found. This was the last | |||||
* \arg DRV_BUSY (2) Search is succeed, plus there are more ROM IDs to found | |||||
* \arg DRV_ERROR (3) Search failed, Reading error | |||||
*/ | |||||
drv_status_en ow_uart_search (ow_uart_t *ow, uint8_t *romid) | |||||
{ | |||||
static uint8_t dec[8]; /*!< | |||||
* Hold the algorithm's select bit when a discrepancy | |||||
* is detected. We use this variable to navigate to the | |||||
* ROM tree as we store the path we take each time (0-1). | |||||
* Each bit represent a bit position in the ROM ID. | |||||
*/ | |||||
static uint8_t pos[8]; /*!< | |||||
* Hold the discrepancy position. We use this variable to | |||||
* navigate to the ROM tree as we store the crossroads(1) we encounter. | |||||
* Each bit represent a bit position in the ROM ID. | |||||
*/ | |||||
uint8_t i, cur[8]; /* Current pass bit position, in a pos[8] like representation of it */ | |||||
uint8_t b, b1, b2; /* bit helper vars */ | |||||
if (ow_uart_reset (ow) != DRV_READY) | |||||
return DRV_NODEV; | |||||
ow_uart_tx (ow, 0xF0); /* Issue search command */ | |||||
for (i=0 ; i<64 ; ++i) { | |||||
/* Get response pair bits */ | |||||
b1 = _read_bit (ow); | |||||
b2 = _read_bit (ow); | |||||
switch (b1 | (b2<<1)) { | |||||
case 0x00: /* 00 - We have discrepancy */ | |||||
_write_bit_u64 (cur, i, 1); | |||||
switch (_cmp_u64 (pos, cur)) { | |||||
default: | |||||
case -1: b = 0; | |||||
_write_bit_u64 (pos, i, 1); break; | |||||
case 0: b = 1; | |||||
_write_bit_u64 (dec, i, 1); break; | |||||
case 1: b = _read_bit_u64 (dec, i); break; | |||||
/*< | |||||
* -1) pos < cur: This discrepancy is the most far for now. | |||||
* Mark position and select 0. | |||||
* 0) pos == cur: This was the last discrepancy in the last pass. | |||||
* Select the other branch this time (1). | |||||
* 1) pos > cur: We had a discrepancy in a MSB than that, in a previous pass. | |||||
* Continue with the last pass decision. | |||||
*/ | |||||
} | |||||
/* Send selection and update romid */ | |||||
_write_bit (ow, b); | |||||
_write_bit_u64 (romid, i, b); | |||||
break; | |||||
case 0x01: /* 01 - All bits of all ROMs are 1s */ | |||||
_write_bit (ow, 1); | |||||
_write_bit_u64 (romid, i, 1); break; | |||||
case 0x02: /* 10 - All bits of all ROMs are 0s */ | |||||
_write_bit (ow, 0); | |||||
_write_bit_u64 (romid, i, 0); break; | |||||
default: | |||||
case 0x03: /* 11 - No device on the bus */ | |||||
_clear_u64 (romid); | |||||
return DRV_NODEV; | |||||
} /* switch (b1 | (b2<<1)) */ | |||||
} /* for */ | |||||
switch (_cmp_u64 (dec, pos)) { | |||||
case -1: return DRV_BUSY; | |||||
case 0: _clear_u64 (dec); | |||||
_clear_u64 (pos); | |||||
return DRV_READY; | |||||
default: | |||||
case 1: _clear_u64 (dec); | |||||
_clear_u64 (pos); | |||||
return DRV_ERROR; | |||||
/*< | |||||
* -1) des < pos: We have more leafs(ROMs) to found | |||||
* 0) des == pos: We have found all the leafs(ROMs) | |||||
* 1) des > pos: We have more decision that discrepancies ?!?!?, Error. | |||||
*/ | |||||
} | |||||
} | |||||
#undef _clear_u64 | |||||
#undef _read_bit_u64 | |||||
#undef _write_bit_u64 | |||||
#undef _ow_is_timings |
@@ -0,0 +1,206 @@ | |||||
/*! | |||||
* \file onewire_uart.h | |||||
* \brief | |||||
* A target independent 1-wire implementation using a microprocessor's uart | |||||
* for bit timing | |||||
* \note | |||||
* This 1-wire implementation is based on MCU UART io functionality. In order | |||||
* to work it needs: | |||||
* 1) A Open drain tx and floating(or pull-up) rx UART pin configuration with both pins | |||||
* connected to the 1-wire bus wire | |||||
* 2) A Transmit function even in blocking/polling mode | |||||
* 3) A receive function even in blocking/polling mode | |||||
* 4) A baudrate set function | |||||
* | |||||
* Copyright (C) 2016 Choutouridis Christos <cchoutou@ece.auth.gr> | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
* | |||||
*/ | |||||
#ifndef __onewire_uart_h__ | |||||
#define __onewire_uart_h__ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#include "driver_types.h" | |||||
#include <string.h> | |||||
/* ================ General Defines ====================*/ | |||||
typedef uint16_t (*ow_uart_rw_ft) (uint8_t); /*!< UART read-write function pointer */ | |||||
typedef drv_status_en (*ow_uart_br_ft) (uint32_t); /*!< UART baudrate modify function pointer */ | |||||
/*! | |||||
* 1-Wire operational state | |||||
*/ | |||||
typedef enum { | |||||
OWS_RESET = 0, /*!< 1-Wire bus is during in Reset state */ | |||||
OWS_OPER /*!< 1-Wire bus is during normal operation */ | |||||
}ow_uart_state_en; | |||||
/*! | |||||
* 1-Wire UART baudrate table | |||||
*/ | |||||
typedef struct { | |||||
uint32_t reset; /*!< Baudrate during reset */ | |||||
uint32_t oper; /*!< Baudrate during normal operation */ | |||||
uint32_t current; /*!< The current baudrate to use as flag */ | |||||
}ow_uart_br_t; | |||||
/*! | |||||
* 1-Wire driver function callback pointers | |||||
* \note | |||||
* The function in this structure provided from the low level driver (usually). | |||||
*/ | |||||
typedef struct { | |||||
ow_uart_rw_ft rw; /*!< Pointer UART read-write function */ | |||||
ow_uart_br_ft br; /*!< Pointer to UART baudrate function */ | |||||
}ow_uart_io_t; | |||||
/*! | |||||
* 1-Wire Data type | |||||
*/ | |||||
typedef struct { | |||||
ow_uart_io_t io; /*!< Callback pointers and direction state */ | |||||
uint32_t timing; /*!< The selected timing mode */ | |||||
ow_uart_br_t baudrate; /*!< The current baudrate configuration */ | |||||
drv_status_en status; /*!< Toolbox driver status */ | |||||
}ow_uart_t; | |||||
/* | |||||
* ============ Helper Macros ============= | |||||
*/ | |||||
/*! | |||||
* 1-Wire speed | |||||
*/ | |||||
#define OW_UART_T_STANDARD (0) | |||||
#define OW_UART_T_OVERDRIVE (1) | |||||
/*! | |||||
* Check if the timing is a valid \ref ow_uart_timing_en value | |||||
*/ | |||||
#define _ow_uart_is_timings(_t_) ( ((_t_) == OW_UART_T_STANDARD) || ((_t_) == OW_UART_T_OVERDRIVE) ) | |||||
/* | |||||
* Timing Diagram | |||||
* -------------------------------------------------- | |||||
* Based on Application Note 214 (www.maxim-ic.com) | |||||
* | |||||
* --- ---- - - - ------- | |||||
* Reset \ / \ X X X / | |||||
* -------------------- - - - - | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ---------- 1024/174 usec -------------> | |||||
* | |||||
* 8 bits, no parity, 1 stop | |||||
* Standard: Overdrive : | |||||
* BR: 9600, BR: 57600 | |||||
* TX: 0xF0, TX: 0xF8 | |||||
* RX: 0xF0 not present RX: 0xF8 not present | |||||
* less if present less if present | |||||
* | |||||
* | |||||
* --- -------------------------------------- | |||||
* Write 1 \ / | |||||
* ---- | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0xFF | |||||
* RX: 0xFF | |||||
* | |||||
* --- ------ | |||||
* Write 0 \ / | |||||
* ------------------------------------- | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0x00 | |||||
* RX: 0x00 | |||||
* | |||||
* --- - - - - - - - - - - - ------ | |||||
* Read \ / X X X X X X X X X X X X X X X / | |||||
* ---- - - - - - - - - - - - | |||||
* RS: | | | | | | | | | | | | |||||
* bit: st 0 1 2 3 4 5 6 7 st | |||||
* < ------------- 87/11 usec -------------> | |||||
* ^ | |||||
* | | |||||
* Master sample | |||||
* | |||||
* 8 bits, no parity, 1 stop | |||||
* standard: BR: 115200 Overdrive: BR: 921600 | |||||
* TX: 0xFF | |||||
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] } | |||||
* | |||||
*/ | |||||
#define _ow_baudrate_standard(_br_) \ | |||||
do { \ | |||||
_br_.reset = 9600; \ | |||||
_br_.oper = 115200; \ | |||||
_br_.current = 9600; \ | |||||
} while (0) | |||||
#define _ow_baudrate_overdrive(_br_) \ | |||||
do { \ | |||||
_br_.reset = 115200; \ | |||||
_br_.oper = 921600; \ | |||||
_br_.current = 115200; \ | |||||
} while (0) | |||||
/* | |||||
* ============= PUBLIC ALCD API ============= | |||||
*/ | |||||
/* | |||||
* Link and Glue functions | |||||
*/ | |||||
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft tx); /*!< link driver's read-write function */ | |||||
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br); /*!< link driver's baudrate function*/ | |||||
/* | |||||
* Set functions | |||||
*/ | |||||
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt); /*!< set 1-wire timing mode */ | |||||
/* | |||||
* User Functions | |||||
*/ | |||||
void ow_uart_deinit (ow_uart_t *ow); /*!< for compatibility */ | |||||
drv_status_en ow_uart_init (ow_uart_t *ow); /*!< for compatibility */ | |||||
drv_status_en | |||||
ow_uart_reset (ow_uart_t *ow); | |||||
uint8_t ow_uart_rx (ow_uart_t *ow); | |||||
void ow_uart_tx (ow_uart_t *ow, byte_t byte); | |||||
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte); | |||||
drv_status_en | |||||
ow_uart_search (ow_uart_t *ow, uint8_t *romid); | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* #ifndef __onewire_uart_h__ */ |
@@ -0,0 +1,495 @@ | |||||
/** | |||||
****************************************************************************** | |||||
* @file stm32f4xx_hal_conf_template.h | |||||
* @author MCD Application Team | |||||
* @brief HAL configuration template file. | |||||
* This file should be copied to the application folder and renamed | |||||
* to stm32f4xx_hal_conf.h. | |||||
****************************************************************************** | |||||
* @attention | |||||
* | |||||
* <h2><center>© Copyright (c) 2017 STMicroelectronics. | |||||
* All rights reserved.</center></h2> | |||||
* | |||||
* This software component is licensed by ST under BSD 3-Clause license, | |||||
* the "License"; You may not use this file except in compliance with the | |||||
* License. You may obtain a copy of the License at: | |||||
* opensource.org/licenses/BSD-3-Clause | |||||
* | |||||
****************************************************************************** | |||||
*/ | |||||
/* Define to prevent recursive inclusion -------------------------------------*/ | |||||
#ifndef __STM32F4xx_HAL_CONF_H | |||||
#define __STM32F4xx_HAL_CONF_H | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/* Exported types ------------------------------------------------------------*/ | |||||
/* Exported constants --------------------------------------------------------*/ | |||||
/* ########################## Module Selection ############################## */ | |||||
/** | |||||
* @brief This is the list of modules to be used in the HAL driver | |||||
*/ | |||||
#define HAL_MODULE_ENABLED | |||||
#define HAL_ADC_MODULE_ENABLED | |||||
#define HAL_CAN_MODULE_ENABLED | |||||
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */ | |||||
#define HAL_CRC_MODULE_ENABLED | |||||
#define HAL_CEC_MODULE_ENABLED | |||||
#define HAL_CRYP_MODULE_ENABLED | |||||
#define HAL_DAC_MODULE_ENABLED | |||||
#define HAL_DCMI_MODULE_ENABLED | |||||
#define HAL_DMA_MODULE_ENABLED | |||||
#define HAL_DMA2D_MODULE_ENABLED | |||||
#define HAL_ETH_MODULE_ENABLED | |||||
#define HAL_FLASH_MODULE_ENABLED | |||||
#define HAL_NAND_MODULE_ENABLED | |||||
#define HAL_NOR_MODULE_ENABLED | |||||
#define HAL_PCCARD_MODULE_ENABLED | |||||
#define HAL_SRAM_MODULE_ENABLED | |||||
#define HAL_SDRAM_MODULE_ENABLED | |||||
#define HAL_HASH_MODULE_ENABLED | |||||
#define HAL_GPIO_MODULE_ENABLED | |||||
#define HAL_EXTI_MODULE_ENABLED | |||||
#define HAL_I2C_MODULE_ENABLED | |||||
#define HAL_SMBUS_MODULE_ENABLED | |||||
#define HAL_I2S_MODULE_ENABLED | |||||
#define HAL_IWDG_MODULE_ENABLED | |||||
#define HAL_LTDC_MODULE_ENABLED | |||||
#define HAL_DSI_MODULE_ENABLED | |||||
#define HAL_PWR_MODULE_ENABLED | |||||
#define HAL_QSPI_MODULE_ENABLED | |||||
#define HAL_RCC_MODULE_ENABLED | |||||
#define HAL_RNG_MODULE_ENABLED | |||||
#define HAL_RTC_MODULE_ENABLED | |||||
#define HAL_SAI_MODULE_ENABLED | |||||
#define HAL_SD_MODULE_ENABLED | |||||
#define HAL_SPI_MODULE_ENABLED | |||||
#define HAL_TIM_MODULE_ENABLED | |||||
#define HAL_UART_MODULE_ENABLED | |||||
#define HAL_USART_MODULE_ENABLED | |||||
#define HAL_IRDA_MODULE_ENABLED | |||||
#define HAL_SMARTCARD_MODULE_ENABLED | |||||
#define HAL_WWDG_MODULE_ENABLED | |||||
#define HAL_CORTEX_MODULE_ENABLED | |||||
#define HAL_PCD_MODULE_ENABLED | |||||
#define HAL_HCD_MODULE_ENABLED | |||||
#define HAL_FMPI2C_MODULE_ENABLED | |||||
#define HAL_SPDIFRX_MODULE_ENABLED | |||||
#define HAL_DFSDM_MODULE_ENABLED | |||||
#define HAL_LPTIM_MODULE_ENABLED | |||||
#define HAL_MMC_MODULE_ENABLED | |||||
/* ########################## HSE/HSI Values adaptation ##################### */ | |||||
/** | |||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application. | |||||
* This value is used by the RCC HAL module to compute the system frequency | |||||
* (when HSE is used as system clock source, directly or through the PLL). | |||||
*/ | |||||
#if !defined (HSE_VALUE) | |||||
#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */ | |||||
#endif /* HSE_VALUE */ | |||||
#if !defined (HSE_STARTUP_TIMEOUT) | |||||
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ | |||||
#endif /* HSE_STARTUP_TIMEOUT */ | |||||
/** | |||||
* @brief Internal High Speed oscillator (HSI) value. | |||||
* This value is used by the RCC HAL module to compute the system frequency | |||||
* (when HSI is used as system clock source, directly or through the PLL). | |||||
*/ | |||||
#if !defined (HSI_VALUE) | |||||
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */ | |||||
#endif /* HSI_VALUE */ | |||||
/** | |||||
* @brief Internal Low Speed oscillator (LSI) value. | |||||
*/ | |||||
#if !defined (LSI_VALUE) | |||||
#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */ | |||||
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz | |||||
The real value may vary depending on the variations | |||||
in voltage and temperature. */ | |||||
/** | |||||
* @brief External Low Speed oscillator (LSE) value. | |||||
*/ | |||||
#if !defined (LSE_VALUE) | |||||
#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */ | |||||
#endif /* LSE_VALUE */ | |||||
#if !defined (LSE_STARTUP_TIMEOUT) | |||||
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ | |||||
#endif /* LSE_STARTUP_TIMEOUT */ | |||||
/** | |||||
* @brief External clock source for I2S peripheral | |||||
* This value is used by the I2S HAL module to compute the I2S clock source | |||||
* frequency, this source is inserted directly through I2S_CKIN pad. | |||||
*/ | |||||
#if !defined (EXTERNAL_CLOCK_VALUE) | |||||
#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/ | |||||
#endif /* EXTERNAL_CLOCK_VALUE */ | |||||
/* Tip: To avoid modifying this file each time you need to use different HSE, | |||||
=== you can define the HSE value in your toolchain compiler preprocessor. */ | |||||
/* ########################### System Configuration ######################### */ | |||||
/** | |||||
* @brief This is the HAL system configuration section | |||||
*/ | |||||
#define VDD_VALUE 3300U /*!< Value of VDD in mv */ | |||||
#define TICK_INT_PRIORITY 0x0FU /*!< tick interrupt priority */ | |||||
#define USE_RTOS 0U | |||||
#define PREFETCH_ENABLE 1U | |||||
#define INSTRUCTION_CACHE_ENABLE 1U | |||||
#define DATA_CACHE_ENABLE 1U | |||||
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */ | |||||
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */ | |||||
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */ | |||||
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */ | |||||
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */ | |||||
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */ | |||||
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */ | |||||
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */ | |||||
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */ | |||||
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */ | |||||
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */ | |||||
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */ | |||||
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */ | |||||
#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */ | |||||
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */ | |||||
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */ | |||||
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */ | |||||
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */ | |||||
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */ | |||||
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */ | |||||
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */ | |||||
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */ | |||||
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */ | |||||
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */ | |||||
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */ | |||||
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */ | |||||
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */ | |||||
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */ | |||||
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */ | |||||
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */ | |||||
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */ | |||||
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */ | |||||
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */ | |||||
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */ | |||||
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */ | |||||
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */ | |||||
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */ | |||||
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */ | |||||
/* ########################## Assert Selection ############################## */ | |||||
/** | |||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the | |||||
* HAL drivers code | |||||
*/ | |||||
/* #define USE_FULL_ASSERT 1U */ | |||||
/* ################## Ethernet peripheral configuration ##################### */ | |||||
/* Section 1 : Ethernet peripheral configuration */ | |||||
/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ | |||||
#define MAC_ADDR0 2U | |||||
#define MAC_ADDR1 0U | |||||
#define MAC_ADDR2 0U | |||||
#define MAC_ADDR3 0U | |||||
#define MAC_ADDR4 0U | |||||
#define MAC_ADDR5 0U | |||||
/* Definition of the Ethernet driver buffers size and count */ | |||||
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ | |||||
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ | |||||
#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */ | |||||
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ | |||||
/* Section 2: PHY configuration section */ | |||||
/* DP83848 PHY Address*/ | |||||
#define DP83848_PHY_ADDRESS 0x01U | |||||
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ | |||||
#define PHY_RESET_DELAY 0x000000FFU | |||||
/* PHY Configuration delay */ | |||||
#define PHY_CONFIG_DELAY 0x00000FFFU | |||||
#define PHY_READ_TO 0x0000FFFFU | |||||
#define PHY_WRITE_TO 0x0000FFFFU | |||||
/* Section 3: Common PHY Registers */ | |||||
#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */ | |||||
#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */ | |||||
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ | |||||
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ | |||||
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ | |||||
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ | |||||
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ | |||||
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ | |||||
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ | |||||
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ | |||||
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ | |||||
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ | |||||
#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ | |||||
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ | |||||
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ | |||||
/* Section 4: Extended PHY Registers */ | |||||
#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */ | |||||
#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */ | |||||
#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */ | |||||
#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ | |||||
#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ | |||||
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ | |||||
#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ | |||||
#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ | |||||
#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ | |||||
#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ | |||||
/* ################## SPI peripheral configuration ########################## */ | |||||
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver | |||||
* Activated: CRC code is present inside driver | |||||
* Deactivated: CRC code cleaned from driver | |||||
*/ | |||||
#define USE_SPI_CRC 1U | |||||
/* Includes ------------------------------------------------------------------*/ | |||||
/** | |||||
* @brief Include module's header file | |||||
*/ | |||||
#ifdef HAL_RCC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_rcc.h" | |||||
#endif /* HAL_RCC_MODULE_ENABLED */ | |||||
#ifdef HAL_GPIO_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_gpio.h" | |||||
#endif /* HAL_GPIO_MODULE_ENABLED */ | |||||
#ifdef HAL_EXTI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_exti.h" | |||||
#endif /* HAL_EXTI_MODULE_ENABLED */ | |||||
#ifdef HAL_DMA_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dma.h" | |||||
#endif /* HAL_DMA_MODULE_ENABLED */ | |||||
#ifdef HAL_CORTEX_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_cortex.h" | |||||
#endif /* HAL_CORTEX_MODULE_ENABLED */ | |||||
#ifdef HAL_ADC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_adc.h" | |||||
#endif /* HAL_ADC_MODULE_ENABLED */ | |||||
#ifdef HAL_CAN_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_can.h" | |||||
#endif /* HAL_CAN_MODULE_ENABLED */ | |||||
#ifdef HAL_CAN_LEGACY_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_can_legacy.h" | |||||
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */ | |||||
#ifdef HAL_CRC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_crc.h" | |||||
#endif /* HAL_CRC_MODULE_ENABLED */ | |||||
#ifdef HAL_CRYP_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_cryp.h" | |||||
#endif /* HAL_CRYP_MODULE_ENABLED */ | |||||
#ifdef HAL_DMA2D_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dma2d.h" | |||||
#endif /* HAL_DMA2D_MODULE_ENABLED */ | |||||
#ifdef HAL_DAC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dac.h" | |||||
#endif /* HAL_DAC_MODULE_ENABLED */ | |||||
#ifdef HAL_DCMI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dcmi.h" | |||||
#endif /* HAL_DCMI_MODULE_ENABLED */ | |||||
#ifdef HAL_ETH_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_eth.h" | |||||
#endif /* HAL_ETH_MODULE_ENABLED */ | |||||
#ifdef HAL_FLASH_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_flash.h" | |||||
#endif /* HAL_FLASH_MODULE_ENABLED */ | |||||
#ifdef HAL_SRAM_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_sram.h" | |||||
#endif /* HAL_SRAM_MODULE_ENABLED */ | |||||
#ifdef HAL_NOR_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_nor.h" | |||||
#endif /* HAL_NOR_MODULE_ENABLED */ | |||||
#ifdef HAL_NAND_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_nand.h" | |||||
#endif /* HAL_NAND_MODULE_ENABLED */ | |||||
#ifdef HAL_PCCARD_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_pccard.h" | |||||
#endif /* HAL_PCCARD_MODULE_ENABLED */ | |||||
#ifdef HAL_SDRAM_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_sdram.h" | |||||
#endif /* HAL_SDRAM_MODULE_ENABLED */ | |||||
#ifdef HAL_HASH_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_hash.h" | |||||
#endif /* HAL_HASH_MODULE_ENABLED */ | |||||
#ifdef HAL_I2C_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_i2c.h" | |||||
#endif /* HAL_I2C_MODULE_ENABLED */ | |||||
#ifdef HAL_SMBUS_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_smbus.h" | |||||
#endif /* HAL_SMBUS_MODULE_ENABLED */ | |||||
#ifdef HAL_I2S_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_i2s.h" | |||||
#endif /* HAL_I2S_MODULE_ENABLED */ | |||||
#ifdef HAL_IWDG_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_iwdg.h" | |||||
#endif /* HAL_IWDG_MODULE_ENABLED */ | |||||
#ifdef HAL_LTDC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_ltdc.h" | |||||
#endif /* HAL_LTDC_MODULE_ENABLED */ | |||||
#ifdef HAL_PWR_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_pwr.h" | |||||
#endif /* HAL_PWR_MODULE_ENABLED */ | |||||
#ifdef HAL_RNG_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_rng.h" | |||||
#endif /* HAL_RNG_MODULE_ENABLED */ | |||||
#ifdef HAL_RTC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_rtc.h" | |||||
#endif /* HAL_RTC_MODULE_ENABLED */ | |||||
#ifdef HAL_SAI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_sai.h" | |||||
#endif /* HAL_SAI_MODULE_ENABLED */ | |||||
#ifdef HAL_SD_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_sd.h" | |||||
#endif /* HAL_SD_MODULE_ENABLED */ | |||||
#ifdef HAL_SPI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_spi.h" | |||||
#endif /* HAL_SPI_MODULE_ENABLED */ | |||||
#ifdef HAL_TIM_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_tim.h" | |||||
#endif /* HAL_TIM_MODULE_ENABLED */ | |||||
#ifdef HAL_UART_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_uart.h" | |||||
#endif /* HAL_UART_MODULE_ENABLED */ | |||||
#ifdef HAL_USART_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_usart.h" | |||||
#endif /* HAL_USART_MODULE_ENABLED */ | |||||
#ifdef HAL_IRDA_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_irda.h" | |||||
#endif /* HAL_IRDA_MODULE_ENABLED */ | |||||
#ifdef HAL_SMARTCARD_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_smartcard.h" | |||||
#endif /* HAL_SMARTCARD_MODULE_ENABLED */ | |||||
#ifdef HAL_WWDG_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_wwdg.h" | |||||
#endif /* HAL_WWDG_MODULE_ENABLED */ | |||||
#ifdef HAL_PCD_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_pcd.h" | |||||
#endif /* HAL_PCD_MODULE_ENABLED */ | |||||
#ifdef HAL_HCD_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_hcd.h" | |||||
#endif /* HAL_HCD_MODULE_ENABLED */ | |||||
#ifdef HAL_DSI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dsi.h" | |||||
#endif /* HAL_DSI_MODULE_ENABLED */ | |||||
#ifdef HAL_QSPI_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_qspi.h" | |||||
#endif /* HAL_QSPI_MODULE_ENABLED */ | |||||
#ifdef HAL_CEC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_cec.h" | |||||
#endif /* HAL_CEC_MODULE_ENABLED */ | |||||
#ifdef HAL_FMPI2C_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_fmpi2c.h" | |||||
#endif /* HAL_FMPI2C_MODULE_ENABLED */ | |||||
#ifdef HAL_SPDIFRX_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_spdifrx.h" | |||||
#endif /* HAL_SPDIFRX_MODULE_ENABLED */ | |||||
#ifdef HAL_DFSDM_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_dfsdm.h" | |||||
#endif /* HAL_DFSDM_MODULE_ENABLED */ | |||||
#ifdef HAL_LPTIM_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_lptim.h" | |||||
#endif /* HAL_LPTIM_MODULE_ENABLED */ | |||||
#ifdef HAL_MMC_MODULE_ENABLED | |||||
#include "stm32f4xx_hal_mmc.h" | |||||
#endif /* HAL_MMC_MODULE_ENABLED */ | |||||
/* Exported macro ------------------------------------------------------------*/ | |||||
#ifdef USE_FULL_ASSERT | |||||
/** | |||||
* @brief The assert_param macro is used for function's parameters check. | |||||
* @param expr If expr is false, it calls assert_failed function | |||||
* which reports the name of the source file and the source | |||||
* line number of the call that failed. | |||||
* If expr is true, it returns no value. | |||||
* @retval None | |||||
*/ | |||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) | |||||
/* Exported functions ------------------------------------------------------- */ | |||||
void assert_failed(uint8_t* file, uint32_t line); | |||||
#else | |||||
#define assert_param(expr) ((void)0U) | |||||
#endif /* USE_FULL_ASSERT */ | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* __STM32F4xx_HAL_CONF_H */ | |||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
@@ -0,0 +1,632 @@ | |||||
/*! | |||||
* \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; | |||||
} |
@@ -0,0 +1,124 @@ | |||||
/*! | |||||
* \file | |||||
* thermostat_shield.h | |||||
* \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> | |||||
*/ | |||||
#ifndef DRIVERS_THERMOSTAT_SHIELD_H_ | |||||
#define DRIVERS_THERMOSTAT_SHIELD_H_ | |||||
#include "NUCLEO_F401RE.h" | |||||
#include "driver_types.h" | |||||
#include "deque08.h" | |||||
/* | |||||
* =============== Digital I/O =============== | |||||
*/ | |||||
/* | |||||
* =============== 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 | |||||
*/ | |||||
void SHIELD_LCD_DB4 (uint8_t en); | |||||
void SHIELD_LCD_DB5 (uint8_t en); | |||||
void SHIELD_LCD_DB6 (uint8_t en); | |||||
void SHIELD_LCD_DB7 (uint8_t en); | |||||
void SHIELD_LCD_RS (uint8_t en); | |||||
void SHIELD_LCD_EN (uint8_t en); | |||||
void SHIELD_LCD_BL (uint8_t en); | |||||
/* | |||||
* =============== LED =============== | |||||
* LED0 -- D4 -- PB5 | |||||
* LED1 -- D3 -- PB3 | |||||
*/ | |||||
void SHIELD_LED0 (uint8_t on); | |||||
void SHIELD_LED1 (uint8_t on); | |||||
#define LED_RED SHIELD_LED0 | |||||
#define LED_GREEN SHIELD_LED1 | |||||
/* | |||||
* =============== BRIDGE =============== | |||||
* BR1 -- D10 -- PB6 | |||||
* BR2 -- D9 -- PC7 | |||||
*/ | |||||
void SHIELD_BR1 (uint8_t on); | |||||
void SHIELD_BR2 (uint8_t on); | |||||
/* | |||||
* =============== SR04 =============== | |||||
* TRIG -- D11 -- PA7 | |||||
* ECHO -- D12 -- PA6 | |||||
*/ | |||||
void SHIELD_TRIG (uint8_t on); | |||||
uint8_t SHIELD_ECHO (void); | |||||
/* | |||||
* ============= 1 Wire USART6 (AF08)=============== | |||||
* 1W_Tx -- PA11 (OD+PU) | |||||
* 1W_Rx -- PA12 (I) | |||||
*/ | |||||
// non-shared resources | |||||
#define _1WIRE_UART_INSTANCE (USART6) | |||||
#define _1WIRE_UART_INIT_BR (9600) | |||||
#define _1WIRE_UART_TIMEOUT (10) /*!< 10msec is good enough */ | |||||
/*! | |||||
* Helper Macros linked to USART used | |||||
*/ | |||||
#define _1WIRE_UART_CLK_ENABLE __HAL_RCC_USART6_CLK_ENABLE | |||||
#define _1WIRE_UART_CLK_DISABLE __HAL_RCC_USART6_CLK_DISABLE | |||||
LLD_Status_en SHIELD_1W_Init (void); | |||||
drv_status_en SHIELD_1W_UART_BR (uint32_t br); | |||||
uint16_t SHIELD_1W_RW (uint8_t byte); | |||||
uint8_t SHIELD_1W_Rx (void); | |||||
uint8_t SHIELD_1W_Tx (uint8_t byte); | |||||
LLD_Status_en SHIELD_Init (void); | |||||
/* | |||||
* ============= Serial console UART2 (AF07)=============== | |||||
* COM_Tx -- PA2 (PP) | |||||
* COM_Rx -- PA3 (I) | |||||
*/ | |||||
#define COM_UART_INSTANCE USART2 | |||||
#define COM_UART_IRQ USART2_IRQn | |||||
#define COM_UART_BAUDRATE (57600) | |||||
#define COM_UART_GETCHAR_TIMEOUT (5) // 5sec | |||||
#define COM_UART_PUTCHAR_TIMEOUT (10) // 1 [CPU time] | |||||
#define COM_BUFFER_SIZE (256) | |||||
/*! | |||||
* Helper Macros linked to USART used | |||||
*/ | |||||
#define _COM_CLK_ENABLE __HAL_RCC_USART2_CLK_ENABLE | |||||
#define _COM_CLK_DISNABLE __HAL_RCC_USART2_CLK_DISABLE | |||||
LLD_Status_en COM_Init (void); | |||||
LLD_Status_en COM_baudrate (uint32_t br); | |||||
int COM_putchar (char c); | |||||
int COM_getchar (void); | |||||
int COM_Transmit (uint8_t *data, int size); | |||||
int COM_CheckReceive (void); | |||||
void COM_ReceiveFlush (void); | |||||
int COM_Receive (uint8_t *data, int size); | |||||
#endif /* DRIVERS_THERMOSTAT_SHIELD_H_ */ |
@@ -0,0 +1,130 @@ | |||||
/* | |||||
* console.c | |||||
* | |||||
* Created on: Jun 28, 2020 | |||||
* Author: hoo2 | |||||
*/ | |||||
#include "console.h" | |||||
static char _buffer[COM_BUFFER_SIZE]; | |||||
static int _cursor; | |||||
static char _ans[512]; | |||||
void parse (char* buffer) { | |||||
int i; | |||||
float_t s; | |||||
if ((strncmp((const void*)buffer, "help", 4) == 0) || | |||||
(strncmp((const void*)buffer, "?", 1) == 0) ) { | |||||
i = sprintf (_ans, "\r\nThermostat commands:\r\n"); | |||||
i += sprintf (&_ans[i], "info : Get information\r\n"); | |||||
i += sprintf (&_ans[i], "set Tset <val> : Set Thermostat\'s temperature\r\n"); | |||||
i += sprintf (&_ans[i], "set Thyst <val> : Set Thermostat\'s hysteresis\r\n"); | |||||
i += sprintf (&_ans[i], "set Pset <val> : Set Proximity\r\n"); | |||||
i += sprintf (&_ans[i], "set Physt <val> : Set Proximity\'s hysteresis\r\n"); | |||||
i += sprintf (&_ans[i], "set mode heating : Set Thermostat to heating mode\r\n"); | |||||
i += sprintf (&_ans[i], "set mode cooling : Set Thermostat to cooling mode\r\n"); | |||||
i += sprintf (&_ans[i], "\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)buffer, "info", 4) == 0) { | |||||
i = sprintf (_ans, "\r\nThermostat data:\r\n"); | |||||
i += sprintf (&_ans[i], "Tcur = %4.1f\r\n", temp_get_current ()); | |||||
i += sprintf (&_ans[i], "Tav = %4.1f\r\n", app_data.Tav); | |||||
i += sprintf (&_ans[i], "Mode = %s\r\n", (settings.mode == HEATING) ? "Heating" : "Cooling"); | |||||
i += sprintf (&_ans[i], "Output = %s\r\n", (app_data.flag_output) ? "On" : "Off"); | |||||
i += sprintf (&_ans[i], "Tset = %4.1f, Hyst = %4.1f\r\n", settings.Tset, settings.Thyst); | |||||
i += sprintf (&_ans[i], "Pset = %4.1f, Hyst = %4.1f\r\n", settings.Pset, settings.Physt); | |||||
i += sprintf (&_ans[i], "\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)buffer, "set ", 4) == 0) { | |||||
if (strncmp((const void*)&buffer[4], "Tset ", 5) == 0) { | |||||
sscanf((const void*)&buffer[9], "%f", &s); | |||||
if (s > -20 && s < 80) { | |||||
settings.Tset = s; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
} | |||||
else | |||||
i = sprintf (_ans, "Error\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)&buffer[4], "Thyst ", 6) == 0) { | |||||
sscanf((const void*)&buffer[10], "%f", &s); | |||||
if (s > 0 && s < 20) { | |||||
settings.Thyst = s; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
} | |||||
else | |||||
i = sprintf (_ans, "Error\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)&buffer[4], "Pset ", 5) == 0) { | |||||
sscanf((const void*)&buffer[9], "%f", &s); | |||||
if (s > 0 && s < 100) | |||||
settings.Pset = s; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)&buffer[4], "Physt ", 6) == 0) { | |||||
sscanf((const void*)&buffer[10], "%f", &s); | |||||
if (s > 0 && s < 50) { | |||||
settings.Physt = s; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
} | |||||
else | |||||
i = sprintf (_ans, "Error\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)&buffer[4], "mode ", 5) == 0) { | |||||
if (strncmp((const void*)&buffer[9], "heating", 7) == 0) { | |||||
settings.mode = HEATING; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
else if (strncmp((const void*)&buffer[9], "cooling", 7) == 0) { | |||||
settings.mode = COOLING; | |||||
i = sprintf (_ans, "OK\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
} | |||||
else { | |||||
i = sprintf (_ans, "Error\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
} | |||||
else { | |||||
i = sprintf (_ans, "Error\r\n"); | |||||
_ans[i] =0; | |||||
} | |||||
COM_Transmit((uint8_t*)_ans, i); | |||||
} | |||||
void console (void) { | |||||
int ch; | |||||
if (COM_CheckReceive()) { | |||||
ch = COM_getchar(); // get character | |||||
COM_putchar((char)ch); // Echo back | |||||
_buffer[_cursor++] = ch; // store | |||||
// Backspace, delete | |||||
if (ch == 0x08 || ch == 0x7F) | |||||
--_cursor; | |||||
if (ch == 0 || ch == '\n' || ch == '\r') { | |||||
COM_putchar('\n'); // Echo an extra '\n' | |||||
_buffer[_cursor -1] = 0; | |||||
_cursor =0; | |||||
parse(_buffer); | |||||
} | |||||
if (_cursor >= COM_BUFFER_SIZE) { | |||||
_buffer[_cursor -1] = 0; | |||||
_cursor =0; | |||||
parse(_buffer); | |||||
} | |||||
} | |||||
} | |||||
@@ -0,0 +1,19 @@ | |||||
/* | |||||
* console.h | |||||
* | |||||
* Created on: Jun 28, 2020 | |||||
* Author: hoo2 | |||||
*/ | |||||
#ifndef CONSOLE_H_ | |||||
#define CONSOLE_H_ | |||||
#include <hal.h> | |||||
#include "thermostat.h" | |||||
#include <string.h> | |||||
extern float_t temp_get_current (void); | |||||
void console (void); | |||||
#endif /* CONSOLE_H_ */ |
@@ -0,0 +1,187 @@ | |||||
/*! | |||||
* \file | |||||
* main.c | |||||
* \brief | |||||
* Main application file | |||||
* | |||||
* Author: Christos Choutouridis AEM: 8997 | |||||
* email : <cchoutou@ece.auth.gr> | |||||
*/ | |||||
#include <hal.h> | |||||
#include "thermostat.h" | |||||
#include "console.h" | |||||
/* | |||||
* Zero initialized globals | |||||
*/ | |||||
app_data_t app_data; | |||||
state_en state; | |||||
// Value initialized globals | |||||
settings_t _Init_settings(settings); | |||||
/* | |||||
* helper api | |||||
*/ | |||||
float_t temp_get_current (void) { | |||||
return (app_data.cur) ? app_data.T[app_data.cur-1] : app_data.T[MEASUREMENTS-1]; | |||||
} | |||||
void control (void) { | |||||
static time_t sample =0; | |||||
time_t now = time(0); // get time | |||||
// Proximity | |||||
if (proximity(&prox) < settings.Pset) | |||||
app_data.flag_proximity = 1; | |||||
else if (proximity(&prox) < settings.Pset + settings.Physt) | |||||
; | |||||
else | |||||
app_data.flag_proximity = 0; | |||||
// Temperature calculation | |||||
if (now - sample >= MEAS_INTERVAL) { | |||||
sample = now; | |||||
app_data.T[app_data.cur] = temp_read(); | |||||
if (++app_data.cur >= MEASUREMENTS) { | |||||
app_data.cur =0; | |||||
float_t f =0; | |||||
for (int i=0 ; i<MEASUREMENTS ; ++i) { | |||||
f += app_data.T[i]; | |||||
} | |||||
app_data.Tav = f / MEASUREMENTS; | |||||
app_data.signal_cycle = 1; | |||||
app_data.flag_init = 0; | |||||
} | |||||
} | |||||
// Output handling | |||||
if (!app_data.flag_init) { | |||||
switch (settings.mode) { | |||||
case HEATING: { | |||||
if (app_data.Tav <= settings.Tset) | |||||
app_data.flag_output = 1; | |||||
else if (app_data.Tav < settings.Tset + settings.Thyst) | |||||
; | |||||
else | |||||
app_data.flag_output = 0; | |||||
} | |||||
break; | |||||
case COOLING: { | |||||
if (app_data.Tav <= settings.Tset - settings.Thyst) | |||||
app_data.flag_output = 0; | |||||
else if (app_data.Tav < settings.Tset) | |||||
; | |||||
else | |||||
app_data.flag_output = 1; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
void display (void) { | |||||
static time_t mark =0; | |||||
char line1[18]; | |||||
char line2[18]; | |||||
time_t now = time(0); | |||||
switch (state) { | |||||
case ST_INIT: | |||||
sprintf(line1, "\fInitializing %c ", (time(0)%2) ? '*' : ' '); | |||||
sprintf(line2, "\n "); | |||||
// escapes | |||||
if (app_data.flag_proximity) | |||||
state = ST_USER; | |||||
else if (app_data.signal_cycle) { | |||||
app_data.signal_cycle =0; | |||||
mark = now; | |||||
state = ST_AVERAGE; | |||||
} | |||||
break; | |||||
case ST_COUNT: | |||||
sprintf(line1, "\fMeasuring %c ", (time(0)%2) ? '*' : ' '); | |||||
sprintf(line2, "\n%s: %s ", | |||||
(settings.mode == HEATING) ? "Heating" : "Cooling", | |||||
(app_data.flag_output) ? "On " : "Off" | |||||
); | |||||
// escapes | |||||
if (app_data.flag_proximity) | |||||
state = ST_USER; | |||||
else if (app_data.signal_cycle) { | |||||
app_data.signal_cycle =0; | |||||
mark = now; | |||||
state = ST_AVERAGE; | |||||
} | |||||
break; | |||||
case ST_AVERAGE: | |||||
sprintf(line1, "\fTav=%4.1f ", app_data.Tav); | |||||
sprintf(line2, "\n%s: %s ", | |||||
(settings.mode == HEATING) ? "Heating" : "Cooling", | |||||
(app_data.flag_output) ? "On " : "Off" | |||||
); | |||||
// escapes | |||||
if (app_data.flag_proximity) | |||||
state = ST_USER; | |||||
else if (now - mark >= UI_AVERAGE_TIME) | |||||
state = ST_COUNT; | |||||
break; | |||||
case ST_USER: | |||||
sprintf(line1, "\fTav=%4.1f T=%4.1f", app_data.Tav, temp_get_current()); | |||||
sprintf(line2, "\n%s: %s ", | |||||
(settings.mode == HEATING) ? "Heating" : "Cooling", | |||||
(app_data.flag_output) ? "On " : "Off" | |||||
); | |||||
// escapes | |||||
if (!app_data.flag_proximity) | |||||
state = ST_COUNT; | |||||
break; | |||||
} | |||||
lcd_puts(line1); | |||||
lcd_puts(line2); | |||||
} | |||||
void outputs (void) { | |||||
static uint8_t pr_output =0; | |||||
if (app_data.flag_init) | |||||
return; | |||||
led_green(app_data.flag_output && settings.mode == COOLING); | |||||
led_red (app_data.flag_output && settings.mode == HEATING); | |||||
if (app_data.flag_output != pr_output) { | |||||
relay(app_data.flag_output); | |||||
pr_output = app_data.flag_output; | |||||
} | |||||
} | |||||
int main(void) { | |||||
hal_hw_init (); | |||||
lcd_init (); | |||||
proximity_init(&prox); | |||||
temp_init (TEMP_11_BIT); | |||||
lcd_enable(1); | |||||
app_data.flag_init = 1; | |||||
while (1) { | |||||
control (); | |||||
display (); | |||||
outputs(); | |||||
console (); | |||||
HAL_Delay(10); | |||||
} | |||||
} |
@@ -0,0 +1,65 @@ | |||||
/* | |||||
* thermostat.h | |||||
* | |||||
* Created on: Jun 27, 2020 | |||||
* Author: hoo2 | |||||
*/ | |||||
#ifndef THERMOSTAT_H_ | |||||
#define THERMOSTAT_H_ | |||||
#define MEAS_WINDOW (120) // [sec] | |||||
#define MEAS_INTERVAL (5) // [sec] | |||||
#define MEASUREMENTS (MEAS_WINDOW / MEAS_INTERVAL) // keep this integer | |||||
#define UI_AVERAGE_TIME (10) // [sec] | |||||
//#define UI_USER_TIME (10) | |||||
typedef float float_t; | |||||
typedef int int_t; | |||||
typedef enum { | |||||
HEATING =0, | |||||
COOLING | |||||
} mode_en; | |||||
typedef struct { | |||||
float_t T[MEASUREMENTS]; | |||||
float_t Tav; | |||||
uint32_t cur; | |||||
uint8_t flag_output; | |||||
uint8_t flag_init; | |||||
uint8_t flag_proximity; | |||||
uint8_t signal_cycle; | |||||
} app_data_t; | |||||
typedef struct { | |||||
mode_en mode; | |||||
float_t Tset; | |||||
float_t Thyst; | |||||
float_t Pset; | |||||
float_t Physt; | |||||
} settings_t; | |||||
typedef enum { | |||||
ST_INIT =0, | |||||
ST_COUNT, | |||||
ST_AVERAGE, | |||||
ST_USER | |||||
} state_en; | |||||
/* | |||||
* globals | |||||
*/ | |||||
extern app_data_t app_data; | |||||
extern state_en state; | |||||
extern settings_t settings; | |||||
#define _Init_settings(s) s = { \ | |||||
.mode = HEATING, \ | |||||
.Tset = 21.0, \ | |||||
.Thyst = 2.0, \ | |||||
.Pset = 75.0, \ | |||||
.Physt = 10.0 \ | |||||
} | |||||
#endif /* THERMOSTAT_H_ */ |