@@ -11,6 +11,7 @@ deliver/ | |||
*.ld | |||
Debug/ | |||
Release/ | |||
*.launch | |||
# Keil related | |||
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_ */ |