From 8033e2dc5d1fe0398e320f75f4700d0064476d7b Mon Sep 17 00:00:00 2001 From: Christos Choutouridis Date: Sun, 28 Jun 2020 16:59:18 +0300 Subject: [PATCH] Assignment 3: Code after testing localy added --- .gitignore | 1 + .../Libraries/drivers/NUCLEO_F401RE.c | 313 +++++++++ .../Libraries/drivers/NUCLEO_F401RE.h | 158 +++++ assignment_3/Libraries/drivers/alcd.c | 507 ++++++++++++++ assignment_3/Libraries/drivers/alcd.h | 189 ++++++ assignment_3/Libraries/drivers/deque08.c | 223 ++++++ assignment_3/Libraries/drivers/deque08.h | 77 +++ assignment_3/Libraries/drivers/driver_types.h | 76 +++ assignment_3/Libraries/drivers/hal.c | 209 ++++++ assignment_3/Libraries/drivers/hal.h | 109 +++ assignment_3/Libraries/drivers/jiffies.c | 367 ++++++++++ assignment_3/Libraries/drivers/jiffies.h | 108 +++ assignment_3/Libraries/drivers/onewire_uart.c | 539 +++++++++++++++ assignment_3/Libraries/drivers/onewire_uart.h | 206 ++++++ .../Libraries/drivers/stm32f4xx_hal_conf.h | 495 ++++++++++++++ .../Libraries/drivers/thermostat_shield.c | 632 ++++++++++++++++++ .../Libraries/drivers/thermostat_shield.h | 124 ++++ assignment_3/src/console.c | 130 ++++ assignment_3/src/console.h | 19 + assignment_3/src/main.c | 187 ++++++ assignment_3/src/thermostat.h | 65 ++ 21 files changed, 4734 insertions(+) create mode 100644 assignment_3/Libraries/drivers/NUCLEO_F401RE.c create mode 100644 assignment_3/Libraries/drivers/NUCLEO_F401RE.h create mode 100644 assignment_3/Libraries/drivers/alcd.c create mode 100644 assignment_3/Libraries/drivers/alcd.h create mode 100644 assignment_3/Libraries/drivers/deque08.c create mode 100644 assignment_3/Libraries/drivers/deque08.h create mode 100644 assignment_3/Libraries/drivers/driver_types.h create mode 100644 assignment_3/Libraries/drivers/hal.c create mode 100644 assignment_3/Libraries/drivers/hal.h create mode 100644 assignment_3/Libraries/drivers/jiffies.c create mode 100644 assignment_3/Libraries/drivers/jiffies.h create mode 100644 assignment_3/Libraries/drivers/onewire_uart.c create mode 100644 assignment_3/Libraries/drivers/onewire_uart.h create mode 100644 assignment_3/Libraries/drivers/stm32f4xx_hal_conf.h create mode 100644 assignment_3/Libraries/drivers/thermostat_shield.c create mode 100644 assignment_3/Libraries/drivers/thermostat_shield.h create mode 100644 assignment_3/src/console.c create mode 100644 assignment_3/src/console.h create mode 100644 assignment_3/src/main.c create mode 100644 assignment_3/src/thermostat.h diff --git a/.gitignore b/.gitignore index c22a5aa..9d4b17f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ deliver/ *.ld Debug/ Release/ +*.launch # Keil related Keil/ diff --git a/assignment_3/Libraries/drivers/NUCLEO_F401RE.c b/assignment_3/Libraries/drivers/NUCLEO_F401RE.c new file mode 100644 index 0000000..e17993e --- /dev/null +++ b/assignment_3/Libraries/drivers/NUCLEO_F401RE.c @@ -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 : + */ +#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; +} diff --git a/assignment_3/Libraries/drivers/NUCLEO_F401RE.h b/assignment_3/Libraries/drivers/NUCLEO_F401RE.h new file mode 100644 index 0000000..4124271 --- /dev/null +++ b/assignment_3/Libraries/drivers/NUCLEO_F401RE.h @@ -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 : + */ + +#ifndef NUCLEO_F401RE_H_ +#define NUCLEO_F401RE_H_ + +#include +#include +#include + +/* + * ========= 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 +#endif +#include + +/* + * 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_ */ diff --git a/assignment_3/Libraries/drivers/alcd.c b/assignment_3/Libraries/drivers/alcd.c new file mode 100644 index 0000000..b56f354 --- /dev/null +++ b/assignment_3/Libraries/drivers/alcd.c @@ -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 . + * + */ + +#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. + * + */ + +#ifndef __alcd_h__ +#define __alcd_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "jiffies.h" +#include "driver_types.h" +#include +#include +#include +#include + + +/* + * 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__ diff --git a/assignment_3/Libraries/drivers/deque08.c b/assignment_3/Libraries/drivers/deque08.c new file mode 100644 index 0000000..0dfc608 --- /dev/null +++ b/assignment_3/Libraries/drivers/deque08.c @@ -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 + * + * 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 . + * + */ +#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; +} diff --git a/assignment_3/Libraries/drivers/deque08.h b/assignment_3/Libraries/drivers/deque08.h new file mode 100644 index 0000000..ba868da --- /dev/null +++ b/assignment_3/Libraries/drivers/deque08.h @@ -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 + * + * 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 . + * + */ +#ifndef __deque08_h__ +#define __deque08_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "driver_types.h" +#include + +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__ diff --git a/assignment_3/Libraries/drivers/driver_types.h b/assignment_3/Libraries/drivers/driver_types.h new file mode 100644 index 0000000..dc1c5ed --- /dev/null +++ b/assignment_3/Libraries/drivers/driver_types.h @@ -0,0 +1,76 @@ +/*! + * \file driver_types.h + * + * Copyright (C) 2020 Choutouridis Christos + * + * 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 . + * + */ + +#ifndef DRIVERS_DRIVER_TYPES_H_ +#define DRIVERS_DRIVER_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + + +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_ */ diff --git a/assignment_3/Libraries/drivers/hal.c b/assignment_3/Libraries/drivers/hal.c new file mode 100644 index 0000000..58cd1fa --- /dev/null +++ b/assignment_3/Libraries/drivers/hal.c @@ -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 . + * + */ +#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_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 ; ireadings[i]; + return ret/PROX_READINGS; +} + + + + diff --git a/assignment_3/Libraries/drivers/hal.h b/assignment_3/Libraries/drivers/hal.h new file mode 100644 index 0000000..9a98cfe --- /dev/null +++ b/assignment_3/Libraries/drivers/hal.h @@ -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 . + * + */ +#ifndef DRIVERS_HAL_H_ +#define DRIVERS_HAL_H_ + +#include +#include +#include +#include +#include +#include +#include + +#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_ */ diff --git a/assignment_3/Libraries/drivers/jiffies.c b/assignment_3/Libraries/drivers/jiffies.c new file mode 100644 index 0000000..ae38db1 --- /dev/null +++ b/assignment_3/Libraries/drivers/jiffies.c @@ -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 . + * + */ +#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 + } +} diff --git a/assignment_3/Libraries/drivers/jiffies.h b/assignment_3/Libraries/drivers/jiffies.h new file mode 100644 index 0000000..af5a300 --- /dev/null +++ b/assignment_3/Libraries/drivers/jiffies.h @@ -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 . + * + */ +#ifndef __jiffies_h__ +#define __jiffies_h__ + +#ifdef __cplusplus + extern "C" { +#endif + +#include +#include +#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__ diff --git a/assignment_3/Libraries/drivers/onewire_uart.c b/assignment_3/Libraries/drivers/onewire_uart.c new file mode 100644 index 0000000..5d799cb --- /dev/null +++ b/assignment_3/Libraries/drivers/onewire_uart.c @@ -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 . + * + */ +#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 diff --git a/assignment_3/Libraries/drivers/onewire_uart.h b/assignment_3/Libraries/drivers/onewire_uart.h new file mode 100644 index 0000000..a8500de --- /dev/null +++ b/assignment_3/Libraries/drivers/onewire_uart.h @@ -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 + * + * 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 . + * + */ +#ifndef __onewire_uart_h__ +#define __onewire_uart_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "driver_types.h" +#include + +/* ================ 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__ */ diff --git a/assignment_3/Libraries/drivers/stm32f4xx_hal_conf.h b/assignment_3/Libraries/drivers/stm32f4xx_hal_conf.h new file mode 100644 index 0000000..37c8780 --- /dev/null +++ b/assignment_3/Libraries/drivers/stm32f4xx_hal_conf.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 + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

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