Browse Source

Assignment 3: Code after testing localy added

tags/v3.0
parent
commit
8033e2dc5d
21 changed files with 4734 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +313
    -0
      assignment_3/Libraries/drivers/NUCLEO_F401RE.c
  3. +158
    -0
      assignment_3/Libraries/drivers/NUCLEO_F401RE.h
  4. +507
    -0
      assignment_3/Libraries/drivers/alcd.c
  5. +189
    -0
      assignment_3/Libraries/drivers/alcd.h
  6. +223
    -0
      assignment_3/Libraries/drivers/deque08.c
  7. +77
    -0
      assignment_3/Libraries/drivers/deque08.h
  8. +76
    -0
      assignment_3/Libraries/drivers/driver_types.h
  9. +209
    -0
      assignment_3/Libraries/drivers/hal.c
  10. +109
    -0
      assignment_3/Libraries/drivers/hal.h
  11. +367
    -0
      assignment_3/Libraries/drivers/jiffies.c
  12. +108
    -0
      assignment_3/Libraries/drivers/jiffies.h
  13. +539
    -0
      assignment_3/Libraries/drivers/onewire_uart.c
  14. +206
    -0
      assignment_3/Libraries/drivers/onewire_uart.h
  15. +495
    -0
      assignment_3/Libraries/drivers/stm32f4xx_hal_conf.h
  16. +632
    -0
      assignment_3/Libraries/drivers/thermostat_shield.c
  17. +124
    -0
      assignment_3/Libraries/drivers/thermostat_shield.h
  18. +130
    -0
      assignment_3/src/console.c
  19. +19
    -0
      assignment_3/src/console.h
  20. +187
    -0
      assignment_3/src/main.c
  21. +65
    -0
      assignment_3/src/thermostat.h

+ 1
- 0
.gitignore View File

@@ -11,6 +11,7 @@ deliver/
*.ld
Debug/
Release/
*.launch

# Keil related
Keil/


+ 313
- 0
assignment_3/Libraries/drivers/NUCLEO_F401RE.c View File

@@ -0,0 +1,313 @@
/*!
* \file
* NUCLEO_F401RE.h
* \brief
* Nucleo F401RE port file. This file contain the implementation of driver
* calls for F401RE board.
*
* Created on: May 23, 2020
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include "NUCLEO_F401RE.h"

/*
* =============== System ===============
*/

static clock_t volatile __ticks; //!< CPU time
static time_t volatile __now; //!< Time in UNIX seconds past 1-Jan-70
static clock_t volatile __sys_freq; //!< The CPU's time frequency (SysTick freq)

/*!
* \brief
* This is the SysTick ISR, micro-system time base service for CPU time.
* \note
* This service implements the SysTick callback function in order
* to provide micro system - os like functionalities to an application
* without RTOS
*/
void SysTick_Handler(void) {
// Time
++__ticks;
if ( !(__ticks % __sys_freq ) )
++__now; // Do not update __now when we have external time system
}


/*!
* \brief This function configures the source of the time base.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* \param sf Tick interrupt frequency.
* \retval HAL status
*/
__weak HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf) {
SystemCoreClockUpdate ();

/* Configure the SysTick to have interrupt in sf time basis */
if (SysTick_Config (SystemCoreClock/sf) != 0)
return HAL_ERROR;
__sys_freq = sf;

/*Configure the SysTick IRQ priority */
NVIC_SetPriority (SysTick_IRQn, 3U);

/* Return function status */
return HAL_OK;
}

/*!
* Select the system frequency without calling the Setting functionality
* \param sf The desired value
* \return The desired value (enable chaining)
*/
__INLINE clock_t HAL_SelectSysTickFreq (clock_t sf){
return __sys_freq =sf;
}

/*!
* \brief Get the __sys_freq.
*/
__INLINE clock_t HAL_GetSysTickFreq (void){
return __sys_freq;
}


/*!
* \brief Reconfigure the SysTick and update __sys_freq
* \param sf Tick interrupt frequency (CPU time)
* \return status of the operation
* \arg 0 Success
* \arg 1 Fail
*/
int HAL_SetSysTickFreq (clock_t sf) {
/*Configure the SysTick to have interrupt in sf time basis*/
if (__sys_freq != sf) {
// Time base configuration
SystemCoreClockUpdate ();
if (SysTick_Config ( (SystemCoreClock>>3)/sf) != 0)
return 1;
else {
__sys_freq = sf;
return 0;
}
}
return 0;
}

// Take over control of SysTick from HAL library

//! disable HAL_InitTick implementation
HAL_StatusTypeDef
HAL_InitTick(uint32_t TickPriority) { return HAL_OK; }

//! Chain GetTick to our implementation
uint32_t HAL_GetTick(void) { return clock(); }

/*!
* \brief This function provides minimum delay (in CPU time) based
* on variable incremented.
* \param Delay specifies the delay time length, in CPU time.
* \note
* uint32_t is implicitly convertible to clock_t and vice versa.
*/
void HAL_Delay(uint32_t Delay) {
uint32_t tickstart = clock();

while((clock() - tickstart) < Delay)
;
}


/*
* ================ Jiffies ======================
*/

int JF_setfreq (uint32_t jf_freq, uint32_t jiffies) {
uint32_t psc=0;

JF_TIMER_CLK_ENABLE();
SystemCoreClockUpdate ();

if (jf_freq)
psc = SystemCoreClock / jf_freq - 1;

if (psc < 0xFFFF) JF_TIMER->PSC = psc;
else return 1;

if (jiffies < 0xFFFF) JF_TIMER->ARR = jiffies;
else return 1;

JF_TIMER->CR1 |= TIM_CR1_CEN;
return 0;
}

/*
* ======== OS like Functionalities ============
*/


//! SysTick frequency getter
__INLINE clock_t get_freq (void) {
return __sys_freq;
}

//! SysTick frequency setter
//! \return True on failure
int set_freq (clock_t sf) {
return HAL_SetSysTickFreq (sf);
}

/*!
* \brief
* determines the processor time.
* \return
* the implementation's best approximation to the processor time
* used by the program since program invocation. The time in
* seconds is the value returned divided by the value of the macro
* CLK_TCK or CLOCKS_PER_SEC
*/
__INLINE clock_t clock (void) {
return (clock_t) __ticks;
}

/*!
* \brief
* Set the processor time used.
* \param c The new CPU time value
* \return
* The implementation's best approximation to the processor time
* used by the program since program invocation. The time in
* seconds is the value returned divided by the value of the macro
* CLK_TCK or CLOCKS_PER_SEC
*/
clock_t setclock (clock_t c) {
return __ticks = c;
}

/*!
* \brief
* determines the current calendar time. The encoding of the value is
* unspecified.
* \return
* The implementations best approximation to the current calendar
* time. If timer is not a null pointer, the return value
* is also assigned to the object it points to.
*/
time_t time (time_t *timer) {
if (timer)
*timer = (time_t)__now;
return (time_t)__now;
}

/*!
* \brief
* Sets the system's idea of the time and date. The time,
* pointed to by t, is measured in seconds since the Epoch, 1970-01-01
* 00:00:00 +0000 (UTC).
* \param t Pointer to new system's time and date.
* \return On success, zero is returned. On error, -1 is returned
*/
int settime (const time_t *t) {
if (t) {
__now = *t;
return 0;
}
else
return -1;
}


/*
* ============== Cycle count ==============
*/
/*!
* Initialize CPU cycle measurement functionality based on DBG
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en CYCLE_Init (void) {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // enable trace
//DWT->LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers
DWT->CYCCNT = 0; // clear DWT cycle counter
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // enable DWT cycle counter
return LLD_OK;
}

//! CPU cycle getter
__INLINE clock_t CYCLE_Get (void) {
return (clock_t)DWT->CYCCNT;
}

//! Helper digital input pin getter
__INLINE uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin) {
return ((port->IDR & pin) != 0) ? 1:0;
}

//! Helper digital output pin setter
__INLINE uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st) {
if (st) port->BSRR = (uint32_t)pin;
else port->BSRR = (uint32_t)pin << 16;
return st;
}

/*
* =============== Digital I/O ===============
* BTN -- PC13
* LED -- PA5 (SB42 is in place) [SB29: PB13]
*/

/*!
* Initialize GPIO port pins for Nucleo Board
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en NUCLEO_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;

// Enable Port clock
__HAL_RCC_GPIOA_CLK_ENABLE ();
__HAL_RCC_GPIOC_CLK_ENABLE ();

// BTN port configuration
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pin = GPIO_PIN_13;
GPIO_InitType.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOC, &GPIO_InitType);

GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_5;

HAL_GPIO_Init(GPIOA, &GPIO_InitType);

return LLD_OK;
}

//! Nucleo's user button reader
uint8_t NUCLEO_BTN (void) {
return _DINx (GPIOC, GPIO_PIN_13);
}

//! Nucleo's LD2 led setter
void NUCLEO_LED (uint8_t on) {
_DOUTx(GPIOA, GPIO_PIN_5, on);
}

/*! Low level driver init functionality
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR Failure
*/
LLD_Status_en NUCLEO_Init (clock_t sys_freq) {
HAL_Init();
HAL_SysTick_Init (sys_freq);
CYCLE_Init ();
NUCLEO_Port_Init ();

return LLD_OK;
}

+ 158
- 0
assignment_3/Libraries/drivers/NUCLEO_F401RE.h View File

@@ -0,0 +1,158 @@
/*!
* \file
* NUCLEO_F401RE.h
* \brief
* Nucleo F401RE port file. This file contain the implementation of driver
* calls for F401RE board.
*
* Created on: May 23, 2020
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/

#ifndef NUCLEO_F401RE_H_
#define NUCLEO_F401RE_H_

#include <stm32f4xx.h>
#include <stm32f4xx_hal.h>
#include <core_cm4.h>

/*
* ========= Data types ========
*/

//! Driver status return type
typedef enum {
LLD_OK = 0, //!< Indicate successful operation
LLD_ERROR //!< Indicate Error
}LLD_Status_en;

typedef uint8_t din_t;
//typedef int adc_t;

#define OFF (0)
#define ON (!OFF)
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif


/*
* =============== System ===============
*/
#if defined ( __GNUC__ ) && !defined (__CC_ARM)
#include <sys/types.h>
#endif
#include <limits.h>

/*
* Also defined in types.h
*/
#ifndef _CLOCK_T_
#if defined (__CC_ARM)
#define _CLOCK_T_ unsigned int
#else
#define _CLOCK_T_ unsigned long
#endif
typedef _CLOCK_T_ clock_t; /*!< CPU time type */
#endif

#ifndef _TIME_T_
#if defined (__CC_ARM)
#define _TIME_T_ unsigned int
#else
#define _TIME_T_ unsigned long
#endif
typedef _TIME_T_ time_t; /*!< date/time in unix secs past 1-Jan-70 type for 68 years*/
#endif

/*
* Helper macros
*/
#define _CLOCK_T_MAX_VALUE_ (ULONG_MAX) //!< Helper macro for maximum signed CPU time calculations

/*!
* Calculate the positive time difference of _t2_ and _t1_, where
* _t1_, _t2_ are clock_t values
* \note
* _t2_ event comes is AFTER _t1_
*
* ex:
* 0 1 2 3 4 5 6 7 8 9
* ^ ^
* | |
* a b
*
* if : t1=a, t2=b then dt = b-a = t2 - t1
* if : t1=b, t2=a then dt = 9 - (b-a) + 1 = UMAX - (t1-t2) + 1
*
*/
#define _CLOCK_DIFF(_t2_, _t1_) ( ((_t2_)>(_t1_)) ? ((_t2_)-(_t1_)) : (_CLOCK_T_MAX_VALUE_ - ((_t1_) - (_t2_)) + 1) )

/*
* CPU time macros
*/
#define msec2CPUtime(_ms_) (((_ms_) * get_freq()) / 1000)
#define sec2CPUtime(_s_) ((_s_) * get_freq())

#define CPUtime2msec(_t_) (((_t_) * 1000) / get_freq())
#define CPUtime2sec(_t_) ((_t_) / get_freq())

HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf);

clock_t HAL_SelectSysTickFreq (clock_t sf);
clock_t HAL_GetSysTickFreq (void);
int HAL_SetSysTickFreq (clock_t sf);

/*
* ================ Jiffies =====================
*/
#define JF_TIMER TIM5
#define JF_TIM_CLOCK_FREQ (1000000) //1MHz it's OK
#define JF_TIM_VALUE (JF_TIMER->CNT)
#define JF_TIMER_CLK_ENABLE __HAL_RCC_TIM5_CLK_ENABLE

int JF_setfreq (uint32_t jf_freq, uint32_t jiffies);

/*
* OS like Functionalities
*/
clock_t get_freq (void);
int set_freq (clock_t sf);

clock_t clock (void);
clock_t setclock (clock_t c);

time_t time (time_t *timer);
int settime (const time_t *t);


/*
* ============== Cycle count ==============
*/
LLD_Status_en CYCLE_Init (void);
clock_t CYCLE_Get (void);

uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin);
uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st);

/*
* =============== Digital I/O ===============
* BTN -- PC13
* LED -- PA5 (SB42 is in place) [SB29: PB13]
*/
LLD_Status_en NUCLEO_Port_Init (void);

uint8_t NUCLEO_BTN (void);
void NUCLEO_LED (uint8_t on);


/*
* ============= Board Init ==============
*/
LLD_Status_en NUCLEO_Init (clock_t sys_freq);

#endif /* NUCLEO_F401RE_H_ */

+ 507
- 0
assignment_3/Libraries/drivers/alcd.c View File

@@ -0,0 +1,507 @@
/*!
* \file alcd.c
* \brief
* A target independent Alpharithmetic LCD driver
*
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "alcd.h"
static int _inc_x (alcd_t *alcd);
static int _dec_x (alcd_t *alcd);
static void _inc_y (alcd_t *alcd);
static void _dec_y (alcd_t *alcd);
static void _set_bus (alcd_t *alcd, int8_t db);
static void _write_data (alcd_t *alcd, int8_t data);
static void _command (alcd_t *alcd, uint8_t c);
static void _character (alcd_t *alcd, uint8_t c);
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y);
/*!
* \brief
* increase cursor's x position. Positions start from 1.
* If the cursor loops returns 1, else returns 0.
* \param alcd pointer to active alcd.
* \return Change line status
*/
static int _inc_x (alcd_t *alcd) {
int ret=0;
if (++alcd->c.x > alcd->columns) {
alcd->c.x = 1;
ret = 1;
}
return ret;
}
/*!
* \brief
* Decrease cursor's x position. Positions start from 1.
* If the cursor loops returns 1, else returns 0.
* \param alcd pointer to active alcd.
* \return none
*/
static int _dec_x (alcd_t *alcd) {
int ret = 0;
if (--alcd->c.x < 1) {
alcd->c.x = alcd->columns;
ret = 1;
}
return ret;
}
/*!
* \brief
* increase cursor's y position. Positions start from 1.
* \param alcd pointer to active alcd.
* \return none
*/
static void _inc_y (alcd_t *alcd) {
if (++alcd->c.y > alcd->lines) {
alcd->c.y = 1;
}
}
/*!
* \brief
* Decrease cursor's y position. Positions start from 1.
* \param alcd pointer to active alcd.
* \return none
*/
static void _dec_y (alcd_t *alcd) {
if (--alcd->c.y < 1) {
alcd->c.y = alcd->lines;
}
}
/*!
* \brief
* Update the bus I/O and send it to the device.
* \param alcd pointer to active alcd.
* \param db the bus data.
* \return none
*/
static void _set_bus (alcd_t *alcd, int8_t db)
{
alcd->io.db4 (db & 0x01); //Update port
alcd->io.db5 (db & 0x02);
alcd->io.db6 (db & 0x04);
alcd->io.db7 (db & 0x08);
jf_delay_us (10); // Wait to settle
alcd->io.en (1); // Pulse out the data
jf_delay_us (10);
alcd->io.en (0);
jf_delay_us (10); // Data hold
}
/*!
* \brief
* Write the byte date to the bus using _set_bus ()
* \param alcd pointer to active alcd.
* \param data the data byte.
* \return none
*/
static void _write_data (alcd_t *alcd, int8_t data)
{
_set_bus (alcd, data >> 4);
_set_bus (alcd, data & 0x0F);
}
/*!
* \brief
* Send a command to alcd
* \param alcd pointer to active alcd.
* \param c the command byte.
* \return none
*/
static void _command (alcd_t *alcd, uint8_t c)
{
alcd->io.rs(0); // Enter command mode
jf_delay_us (100); // Wait
_write_data (alcd, c); // Send
}
/*!
* \brief
* Send a character to alcd
* \param alcd pointer to active alcd.
* \param c the character byte.
* \return none
*/
static void _character (alcd_t *alcd, uint8_t c)
{
alcd->io.rs(1); // Enter character mode
jf_delay_us (100); // Wait
_write_data (alcd, c); // Send
}
/*!
* \brief
* Set the Cursor to LCD's position line (y), column (x) starts from 1,2,...n
* \param alcd pointer to active alcd.
* \param x the x position.
* \param y the y position.
* \return none
*/
static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y)
{
uint8_t cmd;
alcd->c.x = x; // Update alcd data
alcd->c.y = y;
// Calculate address
switch (y) {
default:
case 1: cmd = 0x0; break;
case 2: cmd = 0x40; break;
case 3: cmd = 0x0 + alcd->columns; break;
case 4: cmd = 0x40 + alcd->columns; break;
}
cmd |= (x - 1);
// Calculate command
cmd |= LCD_DDRAMMask;
// Command out the alcd
_command (alcd, cmd);
}
/*
* ============================ Public Functions ============================
*/
/*
* Link and Glue functions
*/
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB4 pin function
* \return none
*/
inline void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db4 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB5 pin function
* \return none
*/
inline void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db5 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB6 pin function
* \return none
*/
inline void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db6 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's DB7 pin function
* \return none
*/
inline void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db7 = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's RS pin function
* \return none
*/
inline void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.rs = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's EN pin function
* \return none
*/
inline void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.en = pfun; }
/*!
* \brief
* Link driver's db4 pin function to io struct.
* \param alcd pointer to active alcd.
* \param pfun driver's BL pin function
* \return none
*/
inline void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.bl = pfun; }
/*!
* \brief
* Send an ascii character to alcd.
* \param alcd pointer to active alcd.
* \param ch the character to send
* \return the character send.
*
* \note
* This is the driver's "putchar()" functionality to glue.
* Tailor this function to redirect stdout to alcd.
*/
int alcd_putchar (alcd_t *alcd, int ch)
{
alcd->status = DRV_BUSY;
// LCD Character dispatcher
switch (ch) {
case 0:
// don't send null termination to device
break;
case '\n':
_inc_y (alcd);
//break; This "no break" is intentional
case '\r':
_set_cursor (alcd, 1, alcd->c.y);
break;
case '\v':
alcd->c.x = alcd->c.y = 1;
_command (alcd, LCD_RETHOME);
jf_delay_us(2000);
break;
case '\f':
//alcd->c.x = alcd->c.y = 1;
_set_cursor (alcd, 1, 1);
//_command (alcd, LCD_CLRSCR);
//jf_delay_us(5000);
//_command (alcd, LCD_RETHOME);
//_set_cursor (alcd, alcd->c.x, alcd->c.y);
jf_delay_us(2000);
break;
case '\b':
if (_dec_x (alcd)) _dec_y (alcd);
_set_cursor (alcd, alcd->c.x, alcd->c.y);
_character (alcd, ' ');
_set_cursor (alcd, alcd->c.x, alcd->c.y);
break;
default:
_character (alcd, ch);
// Increase cursor and loop inside the same line
if (_inc_x (alcd)) _set_cursor (alcd, alcd->c.x, alcd->c.y);
break;
}
// Restore status
alcd->status = DRV_READY;
//ANSI C (C99) compatible mode
return ch;
}
/*
* Set functions
*/
/*!
* \brief
* Set the number of lines for the attached lcd display
* \param alcd pointer to active alcd.
* \param lines The number of lines (usually 2 or 4)
* \return None.
*/
void alcd_set_lines (alcd_t *alcd, int lines) {
alcd->lines = lines;
}
/*!
* \brief
* Set the number of columns for the attached lcd display
* \param alcd pointer to active alcd.
* \param lines The number of columns (usually 16 or 20)
* \return None.
*/
void alcd_set_columns (alcd_t *alcd, int columns) {
alcd->columns = columns;
}
/*
* User Functions
*/
/*!
* \brief
* De-initialize the alcd.
* \param alcd pointer to active alcd.
* \return none
*/
void alcd_deinit (alcd_t *alcd)
{
memset ((void*)alcd, 0, sizeof (alcd_t));
/*!<
* This leaves the status DRV_NOINIT
*/
}
/*!
* \brief
* Initialize the alcd.
* \param alcd pointer to active alcd.
* \return Zero on success, non zero on error
*/
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs)
{
#define _lcd_assert(_x) if (!_x) return alcd->status = DRV_ERROR;
drv_status_en st = jf_probe ();
if (st == DRV_NODEV || st == DRV_BUSY)
return alcd->status = DRV_ERROR;
_lcd_assert (alcd->io.db4);
_lcd_assert (alcd->io.db5);
_lcd_assert (alcd->io.db6);
_lcd_assert (alcd->io.db7);
_lcd_assert (alcd->io.rs);
_lcd_assert (alcd->io.en);
//_lcd_assert (alcd->io.bl);
/*
* We are here, so all its OK. We can (re)initialize alcd.
*/
alcd->status = DRV_NOINIT;
alcd->c.x = alcd->c.y = 1;
alcd->io.en (0);
alcd->io.rs (0);
jf_delay_us (100000);
//Pre-Init phase 8bit at this point
_set_bus (alcd, 0x3);
jf_delay_us(50000);
_set_bus (alcd, 0x3);
jf_delay_us(5000);
_set_bus (alcd, 0x3);
jf_delay_us(5000);
_set_bus (alcd, 0x2); //4bit selection
jf_delay_us(10000);
_command (alcd, fs); //4bit selection and Function Set
jf_delay_us(5000);
_command (alcd, LCD_DISP_OFF); //Display Off Control 4bit for now on
jf_delay_us(5000);
_command (alcd, LCD_CLRSCR); //Clear Display
jf_delay_us(5000);
_command (alcd, LCD_ENTRYMODE); //Entry Mode Set
jf_delay_us(5000);
_command (alcd, LCD_RETHOME);
jf_delay_us(10000);
_command (alcd, LCD_DISP_ON);
jf_delay_us(5000);
//alcd_backlight (alcd, 1);
return alcd->status = DRV_READY;
#undef _lcd_assert
}
/*!
* \brief
* Enables and disables the lcd backlight.
* \param alcd pointer to active alcd.
* \param on
* \arg 0 disable the backlight
* \arg 1 enable the backlight
* \return none
*/
void alcd_backlight (alcd_t *alcd, uint8_t on) {
if (alcd->io.bl)
alcd->io.bl ((on)?1:0);
}
/*!
* \brief
* Enables and disables the entire lcd (+backlight).
* \param alcd pointer to active alcd.
* \param on
* \arg 0 disable the backlight
* \arg 1 enable the backlight
* \return none
*/
void alcd_enable (alcd_t *alcd, uint8_t on)
{
if (on) {
_command (alcd, LCD_DISP_ON);
alcd_backlight (alcd, 1);
} else {
_command (alcd, LCD_DISP_OFF);
alcd_backlight (alcd, 0);
}
}
/*!
* \brief
* Clears screen and returns cursor at home position (1,1).
* \param alcd pointer to active alcd.
* \return none
*/
void alcd_cls (alcd_t *alcd)
{
_command(alcd, LCD_CLRSCR);
jf_delay_us(2000);
_command (alcd, LCD_RETHOME);
jf_delay_us(2000);
}
/*!
* \brief
* Shift alcd left or right for a \a pos characters.
* \param alcd pointer to active alcd.
* \param pos The number of position to shift.
* A positive number shifts lcd data to left, so screen shows the data in the right.
* A negative number shifts lcd data to right, so screen shows the data in the left.
* \return none
*/
void alcd_shift (alcd_t *alcd, int pos)
{
uint8_t i, cmd = LCD_SHIFT_LEFT;
if (pos<0) {
pos = -pos;
cmd = LCD_SHIFT_RIGHT;
}
for (i=0 ; i<pos ; ++i) {
_command (alcd, cmd);
jf_delay_us(100);
}
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
_command (alcd, LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++) {
_character (alcd, charmap[i]);
}
}

+ 189
- 0
assignment_3/Libraries/drivers/alcd.h View File

@@ -0,0 +1,189 @@
/*!
* \file alcd.c
* \brief
* A target independent Alpharithmetic LCD driver
*
* Copyright (C) 2014 Christos Choutouridis (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __alcd_h__
#define __alcd_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "jiffies.h"
#include "driver_types.h"
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
/*
* General Defines
*/
#define ALCD_CLOCK (CLOCK)
/*!
* ----------------------------------------------------
* Hitachi HD44780 - Samsung KS0066U
* ----------------------------------------------------
*
*
* Entry Mode Set -----> 0 0 0 0 0 1 I/D S
* ----------------------------------------------------
* I/D = 1 -->Inciment Curs I/D = 0 Decriment
* S = 1 -->Display shift S = 0 Not
*
*
* DispOnOffControll --> 0 0 0 0 1 D C B
* -------------------------------------------------
* D = Display On
* C = Cursor On
* B = Blinking On
*
*
* Cursor/Display Shift --> 0 0 0 1 S/C R/L x x
* ---------------------------------------------------
* S/C = 1 -->Display Shift S/C = 0 -->Cursor Shift
* R/L = 1 -->Shift Right R/L = 0 -->Shift left
*
*
* FunctionSet ------> 0 0 1 DL N F x x
* ---------------------------------------------------
* DL = 1 -->8bit DL = 0 -->4bit
* N = 1 -->2 lines N = 0 -->1 line
* F = 1 -->5x10 dots F = 0 -->5x8 dots
*
*/
//#define LCD_LINES (4)
//#define LCD_ROWS (16)
#define LCD_CLRSCR (0x01) /*!< Clear Srean Command Number */
#define LCD_RETHOME (0x02) /*!< Cursor home Un-Shift display DDRam as is */
#define LCD_ENTRYMODE (0x06) /*!< Inc Cursor, Don't shift display */
#define LCD_DISP_ON (0x0C) /*!< No Cursos and Blink */
#define LCD_DISP_OFF (0x08)
#define LCD_CUR_DISP (0x14) /*!< Cursor shift right */
#define LCD_FUNSET_2L8 (0x28) /*!< 4bit, 2lines, 5x8 dots */
#define LCD_FUNSET_1L8 (0x20) /*!< 4bit, 1lines, 5x8 dots */
#define LCD_FUNSET_1L10 (0x24) /*!< 4bit, 1lines, 5x10 dots */
#define LCD_SETCGRAMADDR (0x40)
#define LCD_DDRAMMask (0x80) /*!< DDRAM ------------> 1 ADD[7..0] */
#define LCD_BFMask (0x80) /*!< IR ------------> BF AC[6..0] */
#define LCD_ACMask (0x7f) /*!< ____________________________| */
#define LCD_SHIFT_RIGHT (0x1C)
#define LCD_SHIFT_LEFT (0x18)
typedef enum {
ALCD_1Line_5x8 = LCD_FUNSET_1L8,
ALCD_1Line_5x10 = LCD_FUNSET_1L10,
ALCD_2Lines_5x8 = LCD_FUNSET_2L8
} alcd_funset_en;
/*!
* Alpharithmetic LCD Cursor
*/
typedef volatile struct
{
uint8_t x;
uint8_t y;
}alcd_cursor_t;
/*!
* Alpharithmetic LCD Pin assignements.
* Each one can be called xx.DB4(1); or xx.DB4(0); in order to set
* or clear the corresponding pin.
*
* \note These pointers MUST to be assigned from main application.
*/
typedef volatile struct
{
//drv_pinout_ft db0;
//drv_pinout_ft db1;
//drv_pinout_ft db2;
//drv_pinout_ft db3;
drv_pinout_ft db4; /*!< Pointer for DB4 pin */
drv_pinout_ft db5; /*!< Pointer for DB5 pin */
drv_pinout_ft db6; /*!< Pointer for DB6 pin */
drv_pinout_ft db7; /*!< Pointer for DB7 pin */
drv_pinout_ft rs; /*!< Pointer for RS pin */
drv_pinout_ft en; /*!< Pointer for EN pin */
drv_pinout_ft bl; /*!< Pointer for Back Light pin*/
}alcd_io_t;
/*!
* Alpharithmetic LCD Public Data struct
*/
typedef volatile struct
{
alcd_io_t io; //!< Link to IO struct
alcd_cursor_t c; //!< Link to Cursor struct
uint8_t lines; //!< The lines of attached lcd
uint8_t columns; //!< The columns of attached lcd
//uint8_t bus; //!< Bus length, 4 or 8 bit
drv_status_en status; //!< alcd driver status
}alcd_t;
/*
* ============= PUBLIC ALCD API =============
*/
/*
* Link and Glue functions
*/
void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun);
void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun);
int alcd_putchar (alcd_t *alcd, int ch);
/*
* Set functions
*/
void alcd_set_lines (alcd_t *alcd, int lines);
void alcd_set_columns (alcd_t *alcd, int columns);
/*
* User Functions
*/
void alcd_deinit (alcd_t *alcd); /*!< For compatibility */
drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs); /*!< For compatibility */
void alcd_backlight (alcd_t *alcd, uint8_t on); /*!< For compatibility */
void alcd_enable (alcd_t *alcd, uint8_t on); /*!< For compatibility */
void alcd_cls (alcd_t *alcd); /*!< For compatibility */
void alcd_shift (alcd_t *alcd, int pos); /*!< For compatibility */
void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[]);
#ifdef __cplusplus
}
#endif
#endif //#ifndef __alcd_h__

+ 223
- 0
assignment_3/Libraries/drivers/deque08.c View File

@@ -0,0 +1,223 @@
/*!
* \file deque08.c
* \brief
* This file provides double ended queue capability based on a ring buffer
*
* Copyright (C) 2014 Houtouridis Christos <houtouridis.ch@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "deque08.h"
/*
* ============= Private Queue API =============
*/
static iterator_t _preInc(deque08_t *q, iterator_t* it) {
return (++*it >= q->capacity) ? *it=0 : *it;
}
static iterator_t _preDec(deque08_t *q, iterator_t* it) {
return (--*it < 0) ? *it=q->capacity-1 : *it;
}
static iterator_t _postInc(deque08_t *q, iterator_t* it) {
iterator_t ret = *it;
if (++*it >= q->capacity) *it=0;
return ret;
}
static iterator_t _postDec(deque08_t *q, iterator_t* it) {
iterator_t ret = *it;
if (--*it < 0) *it=q->capacity-1;
return ret;
}
/*
* ============= Public Queue API =============
*/
/*
* Link and Glue functions
*/
void deque08_link_buffer (deque08_t *q, byte_t* buf) {
q->m = buf;
}
/*
* Set functions
*/
inline void deque08_set_capacity (deque08_t *q, size_t capacity) {
q->capacity = capacity;
}
/*
* User Functions
*/
/*!
* \brief
* Check if deque is full
* \param q Which deque to check
* \return
* \arg 0 Not full
* \arg 1 Full
*/
int deque08_is_full (deque08_t *q) {
return (q->items == q->capacity) ? 1:0;
}
/*!
* \brief
* Check if deque is empty
* \param q Which deque to check
* \return
* \arg 0 Not empty
* \arg 1 Empty
*/
int deque08_is_empty (deque08_t *q) {
return (q->items) ? 0:1;
}
/*!
* \brief
* Return the number of items on deque
* \param q Which deque to check
*/
int deque08_size (deque08_t *q) {
return q->items;
}
/*!
* \brief
* Discard all items in deque
* \param q Which deque to check
*/
void deque08_flush (deque08_t *q) {
deque08_init(q);
}
/*!
* \brief
* Initialize the queue
* \param queue Which queue to init
*/
void deque08_init (deque08_t *q) {
q->f = 0;
q->r = -1;
q->items =0;
}
/*!
* \brief
* This function push a byte in front of deque.
* \param q Pointer to deque to use
* \param b byte to push
* \return
* \arg 0 Full queue
* \arg 1 Done
*/
int deque08_push_front (deque08_t *q, byte_t b) {
if (deque08_is_full (q) == 1) //full queue
return 0;
q->m [_preDec (q, &q->f)] = b;
++q->items;
return 1;
}
/*!
* \brief
* This function pops a byte from the front of the deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_pop_front (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [_postInc (q, &q->f)];
--q->items;
return 1;
}
/*!
* \brief
* This function push a byte in the back of deque.
* \param q Pointer to deque to use
* \param b byte to push
* \return
* \arg 0 Full queue
* \arg 1 Done
*/
int deque08_push_back (deque08_t *q, byte_t b) {
if (deque08_is_full (q) == 1) //full queue
return 0;
q->m [_preInc (q, &q->r)] = b;
++q->items;
return 1;
}
/*!
* \brief
* This function pops a byte from the back of the deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_pop_back (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [_postDec (q, &q->r)];
--q->items;
return 1;
}
/*!
* \brief
* This function gives the last item in the back of deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_back (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [q->r];
return 1;
}
/*!
* \brief
* This function gives the first item in the front of deque.
* \param q Pointer to deque to use
* \param b Pointer to byte to return
* \return
* \arg 0 Empty queue
* \arg 1 Done
*/
int deque08_front (deque08_t *q, byte_t *b) {
if (deque08_is_empty (q) == 1) //empty queue
return 0;
*b = q->m [q->f];
return 1;
}

+ 77
- 0
assignment_3/Libraries/drivers/deque08.h View File

@@ -0,0 +1,77 @@
/*!
* \file deque08.h
* \brief
* This file provides double ended queue capability based on a ring buffer
*
* Copyright (C) 2014 Houtouridis Christos <houtouridis.ch@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __deque08_h__
#define __deque08_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "driver_types.h"
#include <string.h>
typedef struct {
byte_t *m; /*!< pointer to queue's buffer */
iterator_t capacity; /*!< queue's max item capacity */
iterator_t items; /*!< current item count */
iterator_t f, r; /*!< queue iterators */
}deque08_t;
/*
* ============= PUBLIC EE API =============
*/
/*
* Link and Glue functions
*/
void deque08_link_buffer (deque08_t *q, byte_t* buf);
/*
* Set functions
*/
void deque08_set_capacity (deque08_t *q, size_t capacity);
/*
* User Functions
*/
int deque08_is_full (deque08_t *q);
int deque08_is_empty (deque08_t *q);
int deque08_size (deque08_t *q);
void deque08_flush (deque08_t *q);
void deque08_init (deque08_t *q);
int deque08_push_front (deque08_t *q, byte_t b);
int deque08_pop_front (deque08_t *q, byte_t *b);
int deque08_push_back (deque08_t *q, byte_t b);
int deque08_pop_back (deque08_t *q, byte_t *b);
int deque08_back (deque08_t *q, byte_t *b);
int deque08_front (deque08_t *q, byte_t *b);
#ifdef __cplusplus
}
#endif
#endif //#ifndef __deque08_h__

+ 76
- 0
assignment_3/Libraries/drivers/driver_types.h View File

@@ -0,0 +1,76 @@
/*!
* \file driver_types.h
*
* Copyright (C) 2020 Choutouridis Christos <cchoutou@ece.auth.gr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef DRIVERS_DRIVER_TYPES_H_
#define DRIVERS_DRIVER_TYPES_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>


typedef uint8_t byte_t; /*!< 8 bits wide */
typedef uint16_t word_t; /*!< 16 bits wide */
typedef uint32_t dword_t; /*!< 32 bits wide */

typedef int32_t iterator_t; /*!< general iterator type */

/*!
* This is a driver wide generic driver status type.
* \note
* DRV_NOINIT = 0, so after memset to zero called by XXXX_deinit() the
* module/device will automatically set to NOINIT state.
*/
typedef enum {
DRV_NODEV=-1, /*!< No device/module */ //!< DRV_NODEV
DRV_NOINIT=0, /*!< Module/Device exist but no initialized *///!< DRV_NOINIT
DRV_READY, /*!< Module/Device initialized succesfully */ //!< DRV_READY
DRV_BUSY, /*!< Module/Device busy */ //!< DRV_BUSY
//DRV_COMPLETE, /*!< Module/device operation complete status */
DRV_ERROR /*!< Module/Device error */ //!< DRV_ERROR
}drv_status_en;


typedef enum {
drv_pin_disable = 0,
drv_pin_input,
drv_pin_output
}drv_pin_dir_en;

/*!
* Pin function pointers
* \note
* These function pointers do not correspond to pin levels.
* They correspond to the enable/disable functionality of that pin.
*/
//! @{
typedef uint8_t (*drv_pinin_ft) (void);
typedef void (*drv_pinout_ft) (uint8_t);
typedef uint8_t (*drv_pinio_ft) (uint8_t);
typedef void (*drv_pindir_ft) (drv_pin_dir_en);
//! @}

#ifdef __cplusplus
}
#endif

#endif /* DRIVERS_DRIVER_TYPES_H_ */

+ 209
- 0
assignment_3/Libraries/drivers/hal.c View File

@@ -0,0 +1,209 @@
/*!
* \file hal.c
*
* Copyright (C) 2020 Choutouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "hal.h"


/*
* Public data types / classes
*/
alcd_t alcd;
ow_uart_t ow;

proximity_t prox;

/*!
* Initialize all hardware
* @return
*/
int hal_hw_init (void) {
// Init base board
NUCLEO_Init(1000);
SHIELD_Init ();

// Start Jiffy functionality
jf_link_setfreq (JF_setfreq);
jf_link_value ((jiffy_t*)&JF_TIM_VALUE);
jf_init (JF_TIM_CLOCK_FREQ, 1000);

return 0;
}

/*
* ========== LCD ===========
*/
/*!
* \brief
* Initialize the lcd data. Not the LCD module
*/
void lcd_init (void) {
alcd_link_db4 (&alcd, SHIELD_LCD_DB4);
alcd_link_db5 (&alcd, SHIELD_LCD_DB5);
alcd_link_db6 (&alcd, SHIELD_LCD_DB6);
alcd_link_db7 (&alcd, SHIELD_LCD_DB7);
alcd_link_rs (&alcd, SHIELD_LCD_RS);
alcd_link_en (&alcd, SHIELD_LCD_EN);
alcd_link_bl (&alcd, SHIELD_LCD_BL);

alcd_set_lines (&alcd, 2);
alcd_set_columns (&alcd, 16);

alcd_init (&alcd, (alcd_funset_en)LCD_FUNSET_2L8);
}

__INLINE void lcd_enable (uint8_t en) {
alcd_enable(&alcd, en);
}

__INLINE int lcd_putchar (char c) {
return alcd_putchar(&alcd, c);
}

int lcd_puts (const char *s) {
int i =0;
while (alcd_putchar(&alcd, *s++))
++i;
return i;
}

/*
* ========== Led interface ==========
*/
__INLINE void led_red (uint8_t en) { LED_RED (en); }
__INLINE void led_green (uint8_t en) { LED_GREEN (en); }

/*
* ========= Relay ===========
*/
void relay (uint8_t on) {
switch (on) {
case 0:
SHIELD_BR1(1);
HAL_Delay(100);
SHIELD_BR1(0);
break;
default:
SHIELD_BR2(1);
HAL_Delay(100);
SHIELD_BR2(0);
break;
}
}


/*
* ========= Temperature ===========
*/
uint8_t ds18b20_rom[8];
uint8_t zero_rom[8] = {0};

int temp_init (uint8_t resolution) {
if (!IS_TEMP_RESOLUTION(resolution))
return 1;

ow_uart_link_rw (&ow, (ow_uart_rw_ft)SHIELD_1W_RW);
ow_uart_link_br (&ow, (ow_uart_br_ft)SHIELD_1W_UART_BR);
ow_uart_set_timing (&ow, OW_UART_T_STANDARD);

ow_uart_init (&ow);
ow_uart_search(&ow, ds18b20_rom);

if (!memcmp ((const void*)ds18b20_rom, (const void*)zero_rom, 8))
return 1;

// set resolution to 9-bit
ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, WRITESCRATCH); // write scratchpad
ow_uart_tx (&ow, (byte_t)127); // Th
ow_uart_tx (&ow, (byte_t)-128); // Tl
ow_uart_tx (&ow, resolution); // Configuration 9 bit
HAL_Delay(100);
return 0;
}

float temp_read (void) {
uint8_t t[2];

ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, STARTCONV); // convert temperature
while (ow_uart_rx(&ow) == 0) // Wait for slave to free the bus
;
//HAL_Delay (100);
ow_uart_reset(&ow);
ow_uart_tx (&ow, SKIPROM); // Skip rom
ow_uart_tx (&ow, READSCRATCH); // read scratchpad

t[0] = ow_uart_rx(&ow); // LSB
t[1] = ow_uart_rx(&ow); // MSB
ow_uart_reset(&ow);

t[1] <<= 4;
t[1] |= (t[0] >> 4);
t[0] &= 0x0F;
return t[1] + t[0]/16.0;
}

/*
* ========= Proximity ===========
*/
void proximity_init (proximity_t* p){
for (int i =0 ; i<PROX_READINGS ; ++i)
proximity(p);
}

float_t proximity (proximity_t* p){
float_t ret;
clock_t t1, t2, mark;

SHIELD_TRIG(1); // send pulse and mark cycles
jf_delay_us(10);
SHIELD_TRIG(0);
// wait for response with timeout
mark = clock();
do {
t1 = CYCLE_Get();
if (clock() - mark >= PROX_TIME_MAX)
return -1;
} while (!SHIELD_ECHO());

mark = clock();
do {
t2 = CYCLE_Get();
if (clock() - mark >= PROX_TIME_MAX)
return -1;
} while (SHIELD_ECHO());

SystemCoreClockUpdate();
uint32_t c_usec = SystemCoreClock / 1000000;
// Load value
p->readings[p->iter++] = (c_usec) ? ((t2 - t1)/c_usec) / 58.2 : PROX_MAX_DISTANSE;
p->iter %= PROX_READINGS;

// Return filtered distance
ret =0;
for (int i=0 ; i<PROX_READINGS ; ++i)
ret += p->readings[i];
return ret/PROX_READINGS;
}





+ 109
- 0
assignment_3/Libraries/drivers/hal.h View File

@@ -0,0 +1,109 @@
/*!
* \file hal.h
*
* Copyright (C) 2020 Choutouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef DRIVERS_HAL_H_
#define DRIVERS_HAL_H_

#include <thermostat_shield.h>
#include <alcd.h>
#include <jiffies.h>
#include <onewire_uart.h>
#include <deque08.h>
#include <thermostat.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif


int hal_hw_init (void);

/*
* ========== LCD ===========
*/
void lcd_init (void);
void lcd_enable (uint8_t en) ;
int lcd_putchar (char c);
int lcd_puts (const char *s);

/*
* ========== Led interface ==========
*/
void led_red (uint8_t en);
void led_green (uint8_t en);


/*
* ========= Relay ===========
*/
void relay(uint8_t on);

/*
* ========= Temperature ===========
*/
// OneWire commands
#define SKIPROM 0xCC // Skip ROM matching transition
#define STARTCONV 0x44 // Tells device to take a temperature reading and put it on the scratchpad
#define COPYSCRATCH 0x48 // Copy EEPROM
#define READSCRATCH 0xBE // Read EEPROM
#define WRITESCRATCH 0x4E // Write to EEPROM
#define RECALLSCRATCH 0xB8 // Reload from last known
#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power
#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition

// Device resolution
#define TEMP_9_BIT 0x1F // 9 bit
#define TEMP_10_BIT 0x3F // 10 bit
#define TEMP_11_BIT 0x5F // 11 bit
#define TEMP_12_BIT 0x7F // 12 bit
#define IS_TEMP_RESOLUTION(x) \
((x == TEMP_9_BIT) || (x == TEMP_10_BIT) || (x == TEMP_11_BIT) || (x == TEMP_12_BIT))

int temp_init (uint8_t resolution);
float temp_read (void);

/*
* ========= Proximity ===========
*/
#define PROX_TIME_MAX 25 // [msec]
#define PROX_READINGS 7 // How many readings for averaging
#define PROX_MAX_DISTANSE 450 // [cm]

typedef struct {
float_t readings[7];
int iter;
} proximity_t;

void proximity_init (proximity_t* p);
float_t proximity (proximity_t* p);


/*
* Public data types / classes
*/
extern alcd_t alcd;
extern ow_uart_t ow;
extern proximity_t prox;

#ifdef __cplusplus
}
#endif

#endif /* DRIVERS_HAL_H_ */

+ 367
- 0
assignment_3/Libraries/drivers/jiffies.c View File

@@ -0,0 +1,367 @@
/*
* \file jiffies.c
* \brief
* A target independent jiffy functionality
*
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "jiffies.h"
static jf_t _jf;
#define JF_MAX_TIM_VALUE (0xFFFF) // 16bit counters
/*
* ====================== Public functions ======================
*/
/*
* Link and Glue functions
*/
/*!
* \brief
* Connect the Driver's Set frequency function to jiffy struct
* \note
* This function get a freq value and returns the timers max jiffy value
* (usual this refers to timer'sauto reload value).
*/
void jf_link_setfreq (jf_setfreq_pt pfun) {
_jf.setfreq = (pfun != 0) ? pfun : 0;
}
/*!
* \brief
* Connect the timer's value to jiffy struct
*/
void jf_link_value (jiffy_t* v) {
_jf.value = (v != 0) ? v : 0;
}
/*
* User Functions
*/
/*!
* \brief
* Check jiffy's status
* \return status
*/
inline drv_status_en jf_probe (void) {
return _jf.status;
}
/*!
* \brief
* De-Initialize the jf data and un-connect the functions
* from the driver
*/
void jf_deinit (void)
{
if (_jf.setfreq) _jf.setfreq (0, 0);
memset ((void*)&_jf, 0, sizeof (jf_t));
_jf.status = DRV_NODEV;
}
/*!
* \brief
* Initialize the jf to a desired jiffy frequency
* \note
* This function has no effect if the inner jiffy struct
* is un-connected to driver. So you have to call
* \sa jf_connect_setfreq() and \sa jf_connect_value() first.
* \return The status of the operation
* \arg DRV_ERROR If the init process fail
* \arg DRV_NODEV If there is no linked jiffy HW, no setfreq function
* \arg DRV_READY Success
*/
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies)
{
if (_jf.setfreq) {
_jf.status = DRV_NOINIT;
if ( _jf.setfreq (jf_freq, jiffies) )
return DRV_ERROR;
_jf.jiffies = jiffies;
_jf.freq = jf_freq;
_jf.jp1ms = jf_per_msec ();
_jf.jp1us = jf_per_usec ();
_jf.jp100ns = jf_per_100nsec ();
return _jf.status = DRV_READY;
}
return _jf.status = DRV_NODEV;
}
/*!
* \brief
* Return the maximum jiffy value.
*/
jiffy_t jf_get_jiffies (void){
return _jf.jiffies;
}
/*!
* \brief
* Return the current jiffy value.
* \note
* Usual this function returns the value of a register from a timer peripheral
* in the MCU. Keep in mind that its value is a moving target!
*/
jiffy_t jf_get_jiffy (void){
return *_jf.value;
}
/*!
* \brief
* Return the systems best approximation for jiffies per msec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_msec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 1000);
/* 1
* 1000Hz = ----- , Its not a magic number
* 1msec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* Return the systems best approximation for jiffies per usec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_usec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 1000000);
/* 1
* 1000000Hz = ------ , Its not a magic number
* 1usec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* Return the systems best approximation for jiffies per usec
* \return
* The calculated value or zero if no calculation can apply
*
* \note
* The result tend to differ as the jiffies and freq values decreasing
*/
jiffy_t jf_per_100nsec (void)
{
jiffy_t jf = (jiffy_t)(_jf.freq / 10000000);
/* 1
* 10000000Hz = ------- , Its not a magic number
* 100nsec
*/
if (jf <= 1) return 1;
else return jf;
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 msec.
* \param msec Time in msec for delay
*/
void jf_delay_ms (jtime_t msec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
msec *= _jf.jp1ms;
// Eat the time difference from msec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
msec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (msec>0);
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param usec Time in usec for delay
*/
void jf_delay_us (jtime_t usec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
usec *= _jf.jp1us;
if ((jtime_t)(*_jf.value) - m1 > usec) // Very small delays may return here.
return;
// Eat the time difference from usec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
usec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (usec>0);
}
/*!
* \brief
* A code based delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 100 nsec.
* \param _100nsec Time in 100nsec for delay
*/
void jf_delay_100ns (jtime_t _100nsec)
{
jtime_t m, m2, m1 = (jtime_t)*_jf.value;
_100nsec *= _jf.jp100ns;
if ((jtime_t)(*_jf.value) - m1 > _100nsec) // Very small delays may return here.
return;
// Eat the time difference from _100nsec value.
do {
m2 = (jtime_t)(*_jf.value);
m = m2 - m1;
_100nsec -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
} while (_100nsec>0);
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 msec.
* \param msec Time in msec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_msec (jtime_t msec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp1ms * msec;
}
// Eat the time difference from msec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 1 usec.
* \param usec Time in usec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_usec (jtime_t usec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp1us * usec;
}
// Eat the time difference from usec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}
/*!
* \brief
* A code based polling version delay implementation, using jiffies for timing.
* This is NOT accurate but it ensures that the time passed is always
* more than the requested value.
* The delay values are multiplications of 100 nsec.
* \param
* _100nsec Time in 100nsec for delay
* \return The status of ongoing delay
* \arg 0: Delay time has passed
* \arg 1: Delay is ongoing, keep calling
*/
int jf_check_100nsec (jtime_t _100nsec)
{
static jtime_t m1=-1, cnt;
jtime_t m, m2;
if (m1 == -1) {
m1 = *_jf.value;
cnt = _jf.jp100ns * _100nsec;
}
// Eat the time difference from _100nsec value.
if (cnt>0) {
m2 = (jtime_t)(*_jf.value);
m = m2-m1;
cnt -= (m>=0) ? m : _jf.jiffies + m;
m1 = m2;
return 1; // wait
}
else {
m1 = -1;
return 0; // do not wait any more
}
}

+ 108
- 0
assignment_3/Libraries/drivers/jiffies.h View File

@@ -0,0 +1,108 @@
/*
* \file jiffies.h
* \brief
* A target independent jiffy functionality
*
* Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __jiffies_h__
#define __jiffies_h__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include "driver_types.h"
typedef uint16_t jiffy_t; //!< Jiffy type 2 byte unsigned integer
typedef int32_t jtime_t; //!< Jiffy time type for delay functionalities usec/msec
typedef int (*jf_setfreq_pt) (uint32_t, uint32_t); //!< Pointer to setfreq function \sa setfreq
/*!
* Jiffy inner structure,
* \info
* We use jiffies to count small time intervals and usually this is
* below SysTick Interrupt. So we use an indepentend counter for that.
* Linux names jiffies the Tick per sec. This is toooo big for us.
* We name jiffy each tick of the extra timer.
* The equalivent of linux jiffies is the return value of clock ().
*/
typedef volatile struct {
jf_setfreq_pt setfreq; /*!< Pointer to driver's timer set freq function */
/*
* \note
* This function must get an integer value for timer's desired
* frequency and returns the maximum jiffy value. This usual
* refers to timer's auto reload value.
*/
jiffy_t *value; /*!< Pointer to timers current value */
uint32_t freq; /*!< timer's frequency */
jiffy_t jiffies; /*!< jiffies max value (timer's max value) */
jiffy_t jp1ms; /*!< Jiffies per 1 msec to use in delay function */
jiffy_t jp1us; /*!< Jiffies per 1 usec to use in delay function */
jiffy_t jp100ns; /*!< Jiffies per 100 nsec to use in delay function */
drv_status_en status;
}jf_t;
/*
* ============= PUBLIC jiffy API =============
*/
/*
* Link and Glue functions
*/
void jf_link_setfreq (jf_setfreq_pt pfun);
void jf_link_value (jiffy_t* v);
/*
* Set functions
*/
/*
* User Functions
*/
drv_status_en jf_probe (void);
void jf_deinit (void);
drv_status_en jf_init (uint32_t jf_freq, jiffy_t jiffies);
jiffy_t jf_get_jiffies (void);
jiffy_t jf_get_jiffy (void);
jiffy_t jf_per_msec (void);
jiffy_t jf_per_usec (void);
jiffy_t jf_per_100nsec (void);
void jf_delay_ms (jtime_t msec);
void jf_delay_us (jtime_t usec);
void jf_delay_100ns (jtime_t _100nsec);
int jf_check_msec (jtime_t msec);
int jf_check_usec (jtime_t usec);
int jf_check_100nsec (jtime_t _100nsec);
/*!
* \note
* The Jiffy lib has no jiffy_t target pointer in the API. This means
* that IT CAN BE ONLY ONE jiffy timer per application.
*/
#ifdef __cplusplus
}
#endif
#endif //#ifndef __jiffies_h__

+ 539
- 0
assignment_3/Libraries/drivers/onewire_uart.c View File

@@ -0,0 +1,539 @@
/*!
* \file onewire_uart.c
* \brief
* A target independent 1-wire implementation using a microprocessor's uart
* for bit timing
*
* Copyright (C) 2015 Choutouridis Christos (http://www.houtouridis.net)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "onewire_uart.h"
/*
* ========= Private helper macros ===========
*/
/*!
* Clear a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
*/
#define _clear_u64(_reg_) \
memset ((void*)(_reg_), 0, 8*sizeof(uint8_t))
/*!
* Read a bit value of a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
* \param _bit The bit location we want to read
*/
#define _read_bit_u64(_reg_, _bit_) \
(_reg_[(_bit_)/8] & (1<<((_bit_)%8))) ? 1:0
/*!
* Write/modify a bit value from a virtual 64bit unsigned register.
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param _reg Pointer to register location. Usual the name of
* The array
* \param _bit The bit location we want to set
* \param _v The value we want to set
* \arg 0 Set to zero
* \arg !0 Set to One
*/
#define _write_bit_u64(_reg_, _bit_, _v_) \
do { \
if (_v_) _reg_[(_bit_)/8] |= 1 << ((_bit_)%8); \
else _reg_[(_bit_)/8] &= ~(1 << ((_bit_)%8)); \
} while (0)
/*
* ============= Private functions ===========
*/
/* Data manipulation functions */
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2);
/* Set functions */
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st);
/* Bus functions */
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b);
static uint8_t _read_bit (ow_uart_t *ow);
/*!
* \brief
* Compare two 64bit virtual unsigned registers
* \note
* We use a uint8_t array[8] to represent that kind
* of data for this module
* \param reg1 Pointer to first register location. Usual the name of
* the array
* \param reg1 Pointer to 2nd register location. Usual the name of
* the array
* \return The comparison result
* \arg 0 Registers are equal
* \arg 1 Register 1 is larger than register 2
* \arg -1 Register 2 is larger than register 1
*/
static int _cmp_u64 (uint8_t *reg1, uint8_t *reg2) {
int i;
for (i=7 ; i>=0 ; --i) {
if (reg1[i] > reg2[i]) return 1; /* reg1 > reg2 */
else if (reg1[i] < reg2[i]) return -1; /* reg1 < reg2 */
}
return 0; /* reg1 equal reg2 */
}
/*!
* \brief
* Set UART Baudrate and handle all function calls and data
* manipulation
* \param ow Pointer to select 1-Wire structure for the operation.
* \param st The 1-Wire operational state \sa ow_uart_state_en
* \return The status of the operation
* \arg DRV_ERROR Could not set baudrate (callback pointer function error)
* \arg DRV_READY Success
*/
static drv_status_en _set_baudrate (ow_uart_t *ow, ow_uart_state_en st)
{
uint32_t st_br;
/* Get the desired baudrate */
switch (st) {
case OWS_RESET: st_br = ow->baudrate.reset; break;
default:
case OWS_OPER: st_br = ow->baudrate.oper; break;
}
if (ow->baudrate.current != st_br) {
if (ow->io.br (st_br) != DRV_READY) return DRV_ERROR;
ow->baudrate.current = st_br;
}
return DRV_READY;
}
/*!
* \brief
* Send a 1-Wire write bit
*
* --- --------------------------------------
* Write 1 \ /
* ----
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: 0xFF
*
* --- ------
* Write 0 \ /
* -------------------------------------
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0x00
* RX: 0x00
*
* \param ow Pointer to select 1-Wire structure for the operation.
* \param b The bit to send
* \return Status of the operation
* \arg 0 Success
* \arg 1 Fail
*/
static uint8_t _write_bit (ow_uart_t *ow, uint8_t b)
{
uint8_t w;
uint16_t r;
/*
* Make sure we are at the right baudrate
*/
if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
return 1;
/* Select frame to send and check the bus by evaluating the return value */
w = (b) ? 0xFF : 0x00;
r = ow->io.rw (w);
if (r != w) return 1;
else return 0;
}
/*!
* \brief
* Read a bit from the 1-Wire bus, return it and provide
* the recovery time.
*
* --- - - - - - - - - - - - ------
* Read \ / X X X X X X X X X X X X X X X /
* ---- - - - - - - - - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* ^
* |
* Master sample
*
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
*
* \return The answer
* \arg 0 Read 0
* \arg 1 Read 1 (This is also returned on transition error).
*/
static uint8_t _read_bit (ow_uart_t *ow)
{
uint16_t r;
/*
* Make sure we are at the right baudrate
*/
if (_set_baudrate (ow, OWS_OPER) != DRV_READY)
return 1;
/* Send frame for read */
r = ow->io.rw (0xFF);
/* Dispatch answer */
if (r < 0xFF) return 0;
else return 1;
}
/*
* ============= PUBLIC 1-Wire API =============
*/
/*
* Link and Glue functions
*/
/*!
* \brief link driver's UART read-write function
* \param ow pointer to select 1-Wire structure for the operation.
* \param tx ow_uart_rx_ft pointer to drivers UART rx function
*/
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft rw) {
ow->io.rw = (ow_uart_rw_ft)((rw != 0) ? rw : 0);
}
/*!
* \brief link driver's UART baudrate function
* \param ow pointer to select 1-Wire structure for the operation.
* \param tx ow_uart_tx_ft pointer to drivers UART baudrate function
*/
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br) {
ow->io.br = (ow_uart_br_ft)((br != 0) ? br : 0);
}
/*
* Set functions
*/
/*!
* \brief set 1-wire timing mode and update baudrate table.
* If the owt parameter is not a valid ow_uart_timing_en
* then set timings to OW_STANDTARD.
* \param ow pointer to select 1-Wire structure for the operation.
* \param owt Timing type
* \arg OWT_STANDARD Use standard timing
* \arg OWT_OVERDRIVE Use overdrive timing
*/
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt) {
ow->timing = (_ow_uart_is_timings(owt)) ? owt : OW_UART_T_STANDARD;
switch (owt) {
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
}
}
/*
* User Functions
*/
/*!
* \brief
* De-Initialize the 1-Wire interface and leave bus pin in input state
* \param ow pointer to select 1-Wire structure for the operation.
* \return none
*/
void ow_uart_deinit (ow_uart_t *ow)
{
// Clear data
memset ((void*)ow, 0, sizeof (ow_uart_t));
/*!<
* This leaves the status = DRV_NOINIT
*/
}
/*!
* \brief
* Initialize the 1-Wire interface and leave bus high
* \param ow pointer to select 1-Wire structure for the operation.
* \return The driver status after init.
* \arg DRV_READY
* \arg DRV_ERROR
*/
drv_status_en ow_uart_init (ow_uart_t *ow)
{
// Check requirements
if (!ow->io.rw) return ow->status = DRV_ERROR;
if (!ow->io.br) return ow->status = DRV_ERROR;
// Init the bus
ow->status = DRV_BUSY;
if ( _ow_uart_is_timings(ow->timing) != 1) {
ow->timing = OW_UART_T_STANDARD;
_ow_baudrate_standard (ow->baudrate);
}
switch (ow->timing) {
case OW_UART_T_STANDARD: _ow_baudrate_standard (ow->baudrate); break;
case OW_UART_T_OVERDRIVE: _ow_baudrate_overdrive (ow->baudrate); break;
}
if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
return ow->status = DRV_ERROR;
return ow->status = DRV_READY;
}
/*!
* \brief
* Generate a 1-wire reset
*
* --- ---- - - - -------
* Reset \ / \ X X X /
* -------------------- - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ---------- 1024/174 usec ------------->
*
* 8 bits, no parity, 1 stop
* Standard: Overdrive :
* BR: 9600, BR: 57600
* TX: 0xF0, TX: 0xF8
* RX: 0xF0 not present RX: 0xF8 not present
* less if present less if present
*
* \note Does not handle alarm presence from DS2404/DS1994
* \param None
* \return The status of the operation
* \arg DRV_ERROR Error, callback baudrate error or bus error
* \arg DRV_NODEV If no presence detect was found
* \arg DRV_READY Otherwise
*/
drv_status_en ow_uart_reset (ow_uart_t *ow)
{
uint8_t w;
uint16_t r;
/*
* Make sure we are at the write baudrate
*/
if (_set_baudrate (ow, OWS_RESET) != DRV_READY)
return DRV_ERROR;
/* Select frame to send */
w = (ow->timing == OW_UART_T_OVERDRIVE) ? 0xF8 : 0xF0;
r = ow->io.rw (w);
r = ow->io.rw (w); // Send it twice to make sure
if (w>r) return DRV_READY;
else if (w==r) return DRV_NODEV;
else return DRV_ERROR;
}
/*!
* \brief
* Read a byte from 1-Wire bus
* \param ow pointer to select 1-Wire structure for the operation.
* \return The byte received.
*/
uint8_t ow_uart_rx (ow_uart_t *ow)
{
uint8_t i;
byte_t byte;
for (i=8, byte=0 ; i>0 ; --i) {
byte >>= 1; /* shift bits to right as LSB comes first */
if (_read_bit (ow) != 0) byte |= 0x80; /* Mask bit to MSB */
}
return byte;
}
/*!
* \brief
* Write a byte to 1-Wire bus
* \param ow pointer to select 1-Wire structure for the operation.
* \param b: The byte to write
* \return none
*/
void ow_uart_tx (ow_uart_t *ow, byte_t byte)
{
uint8_t i;
for (i=8 ; i>0 ; --i) {
_write_bit (ow, byte & 0x01); /* Send LSB */
byte >>= 1; /* shift bits to right */
}
}
/*!
* \brief
* Write a byte to 1-Wire bus and read the response
* \param ow Pointer to select 1-Wire structure for the operation.
* \param byte The byte to write
* \return The byte received.
*/
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte)
{
uint8_t i;
byte_t ret;
for (i=8, ret=0 ; i>0 ; --i) {
ret >>= 1; /* shift read bits to right as LSB comes first */
if ((byte & 0x01) != 0) ret |= (_read_bit (ow) != 0) ? 0x80 : 0x0;
else _write_bit (ow, 0);
byte >>= 1; /* shift bits to right */
/*!<
* If the bit is 1 we use the read sequence, as it has the same
* waveform with write-1 and we get the slave response
* If the bit is 0, we can not read the slave response so we just write-0
*/
}
return byte;
}
/*!
* \brief
* 1-Wire search algorithm based on maxim-ic application note 187
*
* \param ow Pointer to select 1-Wire structure for the operation.
* \param romid Pointer to romid to return. If the search is success
* this points to and 64bit long array with ROM ID
* \return The status of the search
* \arg DRV_NODEV (-1) Search was failed, No device found
* \arg DRV_READY (1) Search is complete, all ROM IDs was found. This was the last
* \arg DRV_BUSY (2) Search is succeed, plus there are more ROM IDs to found
* \arg DRV_ERROR (3) Search failed, Reading error
*/
drv_status_en ow_uart_search (ow_uart_t *ow, uint8_t *romid)
{
static uint8_t dec[8]; /*!<
* Hold the algorithm's select bit when a discrepancy
* is detected. We use this variable to navigate to the
* ROM tree as we store the path we take each time (0-1).
* Each bit represent a bit position in the ROM ID.
*/
static uint8_t pos[8]; /*!<
* Hold the discrepancy position. We use this variable to
* navigate to the ROM tree as we store the crossroads(1) we encounter.
* Each bit represent a bit position in the ROM ID.
*/
uint8_t i, cur[8]; /* Current pass bit position, in a pos[8] like representation of it */
uint8_t b, b1, b2; /* bit helper vars */
if (ow_uart_reset (ow) != DRV_READY)
return DRV_NODEV;
ow_uart_tx (ow, 0xF0); /* Issue search command */
for (i=0 ; i<64 ; ++i) {
/* Get response pair bits */
b1 = _read_bit (ow);
b2 = _read_bit (ow);
switch (b1 | (b2<<1)) {
case 0x00: /* 00 - We have discrepancy */
_write_bit_u64 (cur, i, 1);
switch (_cmp_u64 (pos, cur)) {
default:
case -1: b = 0;
_write_bit_u64 (pos, i, 1); break;
case 0: b = 1;
_write_bit_u64 (dec, i, 1); break;
case 1: b = _read_bit_u64 (dec, i); break;
/*<
* -1) pos < cur: This discrepancy is the most far for now.
* Mark position and select 0.
* 0) pos == cur: This was the last discrepancy in the last pass.
* Select the other branch this time (1).
* 1) pos > cur: We had a discrepancy in a MSB than that, in a previous pass.
* Continue with the last pass decision.
*/
}
/* Send selection and update romid */
_write_bit (ow, b);
_write_bit_u64 (romid, i, b);
break;
case 0x01: /* 01 - All bits of all ROMs are 1s */
_write_bit (ow, 1);
_write_bit_u64 (romid, i, 1); break;
case 0x02: /* 10 - All bits of all ROMs are 0s */
_write_bit (ow, 0);
_write_bit_u64 (romid, i, 0); break;
default:
case 0x03: /* 11 - No device on the bus */
_clear_u64 (romid);
return DRV_NODEV;
} /* switch (b1 | (b2<<1)) */
} /* for */
switch (_cmp_u64 (dec, pos)) {
case -1: return DRV_BUSY;
case 0: _clear_u64 (dec);
_clear_u64 (pos);
return DRV_READY;
default:
case 1: _clear_u64 (dec);
_clear_u64 (pos);
return DRV_ERROR;
/*<
* -1) des < pos: We have more leafs(ROMs) to found
* 0) des == pos: We have found all the leafs(ROMs)
* 1) des > pos: We have more decision that discrepancies ?!?!?, Error.
*/
}
}
#undef _clear_u64
#undef _read_bit_u64
#undef _write_bit_u64
#undef _ow_is_timings

+ 206
- 0
assignment_3/Libraries/drivers/onewire_uart.h View File

@@ -0,0 +1,206 @@
/*!
* \file onewire_uart.h
* \brief
* A target independent 1-wire implementation using a microprocessor's uart
* for bit timing
* \note
* This 1-wire implementation is based on MCU UART io functionality. In order
* to work it needs:
* 1) A Open drain tx and floating(or pull-up) rx UART pin configuration with both pins
* connected to the 1-wire bus wire
* 2) A Transmit function even in blocking/polling mode
* 3) A receive function even in blocking/polling mode
* 4) A baudrate set function
*
* Copyright (C) 2016 Choutouridis Christos <cchoutou@ece.auth.gr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __onewire_uart_h__
#define __onewire_uart_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "driver_types.h"
#include <string.h>
/* ================ General Defines ====================*/
typedef uint16_t (*ow_uart_rw_ft) (uint8_t); /*!< UART read-write function pointer */
typedef drv_status_en (*ow_uart_br_ft) (uint32_t); /*!< UART baudrate modify function pointer */
/*!
* 1-Wire operational state
*/
typedef enum {
OWS_RESET = 0, /*!< 1-Wire bus is during in Reset state */
OWS_OPER /*!< 1-Wire bus is during normal operation */
}ow_uart_state_en;
/*!
* 1-Wire UART baudrate table
*/
typedef struct {
uint32_t reset; /*!< Baudrate during reset */
uint32_t oper; /*!< Baudrate during normal operation */
uint32_t current; /*!< The current baudrate to use as flag */
}ow_uart_br_t;
/*!
* 1-Wire driver function callback pointers
* \note
* The function in this structure provided from the low level driver (usually).
*/
typedef struct {
ow_uart_rw_ft rw; /*!< Pointer UART read-write function */
ow_uart_br_ft br; /*!< Pointer to UART baudrate function */
}ow_uart_io_t;
/*!
* 1-Wire Data type
*/
typedef struct {
ow_uart_io_t io; /*!< Callback pointers and direction state */
uint32_t timing; /*!< The selected timing mode */
ow_uart_br_t baudrate; /*!< The current baudrate configuration */
drv_status_en status; /*!< Toolbox driver status */
}ow_uart_t;
/*
* ============ Helper Macros =============
*/
/*!
* 1-Wire speed
*/
#define OW_UART_T_STANDARD (0)
#define OW_UART_T_OVERDRIVE (1)
/*!
* Check if the timing is a valid \ref ow_uart_timing_en value
*/
#define _ow_uart_is_timings(_t_) ( ((_t_) == OW_UART_T_STANDARD) || ((_t_) == OW_UART_T_OVERDRIVE) )
/*
* Timing Diagram
* --------------------------------------------------
* Based on Application Note 214 (www.maxim-ic.com)
*
* --- ---- - - - -------
* Reset \ / \ X X X /
* -------------------- - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ---------- 1024/174 usec ------------->
*
* 8 bits, no parity, 1 stop
* Standard: Overdrive :
* BR: 9600, BR: 57600
* TX: 0xF0, TX: 0xF8
* RX: 0xF0 not present RX: 0xF8 not present
* less if present less if present
*
*
* --- --------------------------------------
* Write 1 \ /
* ----
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: 0xFF
*
* --- ------
* Write 0 \ /
* -------------------------------------
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0x00
* RX: 0x00
*
* --- - - - - - - - - - - - ------
* Read \ / X X X X X X X X X X X X X X X /
* ---- - - - - - - - - - - -
* RS: | | | | | | | | | | |
* bit: st 0 1 2 3 4 5 6 7 st
* < ------------- 87/11 usec ------------->
* ^
* |
* Master sample
*
* 8 bits, no parity, 1 stop
* standard: BR: 115200 Overdrive: BR: 921600
* TX: 0xFF
* RX: {1 - 0xFF, 0 - [0x00 - 0xFE] }
*
*/
#define _ow_baudrate_standard(_br_) \
do { \
_br_.reset = 9600; \
_br_.oper = 115200; \
_br_.current = 9600; \
} while (0)
#define _ow_baudrate_overdrive(_br_) \
do { \
_br_.reset = 115200; \
_br_.oper = 921600; \
_br_.current = 115200; \
} while (0)
/*
* ============= PUBLIC ALCD API =============
*/
/*
* Link and Glue functions
*/
void ow_uart_link_rw (ow_uart_t *ow, ow_uart_rw_ft tx); /*!< link driver's read-write function */
void ow_uart_link_br (ow_uart_t *ow, ow_uart_br_ft br); /*!< link driver's baudrate function*/
/*
* Set functions
*/
void ow_uart_set_timing (ow_uart_t *ow, uint32_t owt); /*!< set 1-wire timing mode */
/*
* User Functions
*/
void ow_uart_deinit (ow_uart_t *ow); /*!< for compatibility */
drv_status_en ow_uart_init (ow_uart_t *ow); /*!< for compatibility */
drv_status_en
ow_uart_reset (ow_uart_t *ow);
uint8_t ow_uart_rx (ow_uart_t *ow);
void ow_uart_tx (ow_uart_t *ow, byte_t byte);
uint8_t ow_uart_rw (ow_uart_t *ow, byte_t byte);
drv_status_en
ow_uart_search (ow_uart_t *ow, uint8_t *romid);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef __onewire_uart_h__ */

+ 495
- 0
assignment_3/Libraries/drivers/stm32f4xx_hal_conf.h View File

@@ -0,0 +1,495 @@
/**
******************************************************************************
* @file stm32f4xx_hal_conf_template.h
* @author MCD Application Team
* @brief HAL configuration template file.
* This file should be copied to the application folder and renamed
* to stm32f4xx_hal_conf.h.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4xx_HAL_CONF_H
#define __STM32F4xx_HAL_CONF_H

#ifdef __cplusplus
extern "C" {
#endif

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
#define HAL_CAN_MODULE_ENABLED
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
#define HAL_CRC_MODULE_ENABLED
#define HAL_CEC_MODULE_ENABLED
#define HAL_CRYP_MODULE_ENABLED
#define HAL_DAC_MODULE_ENABLED
#define HAL_DCMI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_DMA2D_MODULE_ENABLED
#define HAL_ETH_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_NAND_MODULE_ENABLED
#define HAL_NOR_MODULE_ENABLED
#define HAL_PCCARD_MODULE_ENABLED
#define HAL_SRAM_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
#define HAL_HASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_SMBUS_MODULE_ENABLED
#define HAL_I2S_MODULE_ENABLED
#define HAL_IWDG_MODULE_ENABLED
#define HAL_LTDC_MODULE_ENABLED
#define HAL_DSI_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_QSPI_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLED
#define HAL_SAI_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
#define HAL_IRDA_MODULE_ENABLED
#define HAL_SMARTCARD_MODULE_ENABLED
#define HAL_WWDG_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_PCD_MODULE_ENABLED
#define HAL_HCD_MODULE_ENABLED
#define HAL_FMPI2C_MODULE_ENABLED
#define HAL_SPDIFRX_MODULE_ENABLED
#define HAL_DFSDM_MODULE_ENABLED
#define HAL_LPTIM_MODULE_ENABLED
#define HAL_MMC_MODULE_ENABLED

/* ########################## HSE/HSI Values adaptation ##################### */
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */

/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz */
#endif /* HSI_VALUE */

/**
* @brief Internal Low Speed oscillator (LSI) value.
*/
#if !defined (LSI_VALUE)
#define LSI_VALUE 32000U /*!< LSI Typical Value in Hz */
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature. */
/**
* @brief External Low Speed oscillator (LSE) value.
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE 32768U /*!< Value of the External Low Speed oscillator in Hz */
#endif /* LSE_VALUE */

#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */

/**
* @brief External clock source for I2S peripheral
* This value is used by the I2S HAL module to compute the I2S clock source
* frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined (EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE 12288000U /*!< Value of the External oscillator in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */

/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */

/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY 0x0FU /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1U
#define INSTRUCTION_CACHE_ENABLE 1U
#define DATA_CACHE_ENABLE 1U

#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
#define USE_HAL_FMPI2C_REGISTER_CALLBACKS 0U /* FMPI2C register callback disabled */
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */

/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */

/* ################## Ethernet peripheral configuration ##################### */

/* Section 1 : Ethernet peripheral configuration */

/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */
#define MAC_ADDR0 2U
#define MAC_ADDR1 0U
#define MAC_ADDR2 0U
#define MAC_ADDR3 0U
#define MAC_ADDR4 0U
#define MAC_ADDR5 0U

/* Definition of the Ethernet driver buffers size and count */
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */
#define ETH_RXBUFNB 4U /* 4 Rx buffers of size ETH_RX_BUF_SIZE */
#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */

/* Section 2: PHY configuration section */

/* DP83848 PHY Address*/
#define DP83848_PHY_ADDRESS 0x01U
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY 0x000000FFU
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY 0x00000FFFU

#define PHY_READ_TO 0x0000FFFFU
#define PHY_WRITE_TO 0x0000FFFFU

/* Section 3: Common PHY Registers */

#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */
#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */
#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */
#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */
#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */
#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */
#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */
#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */
#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */

#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */
#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */
#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */
/* Section 4: Extended PHY Registers */

#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */
#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */
#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */
#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */
#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */
#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */

#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */
#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */

#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */
#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */

/* ################## SPI peripheral configuration ########################## */

/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
* Activated: CRC code is present inside driver
* Deactivated: CRC code cleaned from driver
*/

#define USE_SPI_CRC 1U

/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/

#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32f4xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */

#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32f4xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */

#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32f4xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */

#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32f4xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32f4xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */

#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32f4xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */

#ifdef HAL_CAN_MODULE_ENABLED
#include "stm32f4xx_hal_can.h"
#endif /* HAL_CAN_MODULE_ENABLED */

#ifdef HAL_CAN_LEGACY_MODULE_ENABLED
#include "stm32f4xx_hal_can_legacy.h"
#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */

#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32f4xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */

#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32f4xx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */

#ifdef HAL_DMA2D_MODULE_ENABLED
#include "stm32f4xx_hal_dma2d.h"
#endif /* HAL_DMA2D_MODULE_ENABLED */

#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32f4xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */

#ifdef HAL_DCMI_MODULE_ENABLED
#include "stm32f4xx_hal_dcmi.h"
#endif /* HAL_DCMI_MODULE_ENABLED */

#ifdef HAL_ETH_MODULE_ENABLED
#include "stm32f4xx_hal_eth.h"
#endif /* HAL_ETH_MODULE_ENABLED */

#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32f4xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_SRAM_MODULE_ENABLED
#include "stm32f4xx_hal_sram.h"
#endif /* HAL_SRAM_MODULE_ENABLED */

#ifdef HAL_NOR_MODULE_ENABLED
#include "stm32f4xx_hal_nor.h"
#endif /* HAL_NOR_MODULE_ENABLED */

#ifdef HAL_NAND_MODULE_ENABLED
#include "stm32f4xx_hal_nand.h"
#endif /* HAL_NAND_MODULE_ENABLED */

#ifdef HAL_PCCARD_MODULE_ENABLED
#include "stm32f4xx_hal_pccard.h"
#endif /* HAL_PCCARD_MODULE_ENABLED */
#ifdef HAL_SDRAM_MODULE_ENABLED
#include "stm32f4xx_hal_sdram.h"
#endif /* HAL_SDRAM_MODULE_ENABLED */

#ifdef HAL_HASH_MODULE_ENABLED
#include "stm32f4xx_hal_hash.h"
#endif /* HAL_HASH_MODULE_ENABLED */

#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32f4xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */

#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32f4xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */

#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32f4xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */

#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32f4xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */

#ifdef HAL_LTDC_MODULE_ENABLED
#include "stm32f4xx_hal_ltdc.h"
#endif /* HAL_LTDC_MODULE_ENABLED */

#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32f4xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */

#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32f4xx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */

#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32f4xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */

#ifdef HAL_SAI_MODULE_ENABLED
#include "stm32f4xx_hal_sai.h"
#endif /* HAL_SAI_MODULE_ENABLED */

#ifdef HAL_SD_MODULE_ENABLED
#include "stm32f4xx_hal_sd.h"
#endif /* HAL_SD_MODULE_ENABLED */

#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32f4xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */

#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32f4xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */

#ifdef HAL_UART_MODULE_ENABLED
#include "stm32f4xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */

#ifdef HAL_USART_MODULE_ENABLED
#include "stm32f4xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */

#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32f4xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */

#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32f4xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */

#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32f4xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */

#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32f4xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */

#ifdef HAL_HCD_MODULE_ENABLED
#include "stm32f4xx_hal_hcd.h"
#endif /* HAL_HCD_MODULE_ENABLED */
#ifdef HAL_DSI_MODULE_ENABLED
#include "stm32f4xx_hal_dsi.h"
#endif /* HAL_DSI_MODULE_ENABLED */

#ifdef HAL_QSPI_MODULE_ENABLED
#include "stm32f4xx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */

#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32f4xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */

#ifdef HAL_FMPI2C_MODULE_ENABLED
#include "stm32f4xx_hal_fmpi2c.h"
#endif /* HAL_FMPI2C_MODULE_ENABLED */

#ifdef HAL_SPDIFRX_MODULE_ENABLED
#include "stm32f4xx_hal_spdifrx.h"
#endif /* HAL_SPDIFRX_MODULE_ENABLED */

#ifdef HAL_DFSDM_MODULE_ENABLED
#include "stm32f4xx_hal_dfsdm.h"
#endif /* HAL_DFSDM_MODULE_ENABLED */

#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32f4xx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */

#ifdef HAL_MMC_MODULE_ENABLED
#include "stm32f4xx_hal_mmc.h"
#endif /* HAL_MMC_MODULE_ENABLED */

/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */


#ifdef __cplusplus
}
#endif

#endif /* __STM32F4xx_HAL_CONF_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

+ 632
- 0
assignment_3/Libraries/drivers/thermostat_shield.c View File

@@ -0,0 +1,632 @@
/*!
* \file
* thermostat_shield.c
* \brief
* Nucleo thermostat shield port file. This file contain the implementation of driver
* calls for the shield.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include "thermostat_shield.h"


/*
* =============== Digital I/O ===============
*/
static void SHIELD_LCD_Port_Init (void);
static void SHIELD_LED_Port_Init (void);
static void SHIELD_BRIDGE_Port_Init (void);
static void SHIELD_SR04_Port_Init (void);

/*
* =============== LCD ===============
* LCD_BD4 -- D8 -- PA9
* LCD_BD5 -- D7 -- PA8
* LCD_BD6 -- D6 -- PB10
* LCD_BD7 -- D5 -- PB4
* LCD_RS -- D15 -- PB8
* LCD_EN -- D14 -- PB9
* LCD_BL -- D2 -- PA10
*/
static void SHIELD_LCD_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;

__HAL_RCC_GPIOA_CLK_ENABLE ();
__HAL_RCC_GPIOB_CLK_ENABLE ();

GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);

GPIO_InitType.Pin = GPIO_PIN_4 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LCD_DB4 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_9, en); }
void SHIELD_LCD_DB5 (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_8, en); }
void SHIELD_LCD_DB6 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_10, en); }
void SHIELD_LCD_DB7 (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_4, en); }
void SHIELD_LCD_RS (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_8, en); }
void SHIELD_LCD_EN (uint8_t en) { _DOUTx(GPIOB, GPIO_PIN_9, en); }
void SHIELD_LCD_BL (uint8_t en) { _DOUTx(GPIOA, GPIO_PIN_10, en); }

/*
* =============== LED ===============
* LED0 -- D4 -- PB5
* LED1 -- D3 -- PB3
*/
static void SHIELD_LED_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;

__HAL_RCC_GPIOB_CLK_ENABLE ();

GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_3 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
}
void SHIELD_LED0 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_5, on); }
void SHIELD_LED1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_3, on); }

/*
* =============== BRIDGE ===============
* BR1 -- D10 -- PB6
* BR2 -- D9 -- PC7
*/
static void SHIELD_BRIDGE_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;

__HAL_RCC_GPIOB_CLK_ENABLE ();
__HAL_RCC_GPIOC_CLK_ENABLE ();

GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOC, &GPIO_InitType);
}
void SHIELD_BR1 (uint8_t on) { _DOUTx(GPIOB, GPIO_PIN_6, on); }
void SHIELD_BR2 (uint8_t on) { _DOUTx(GPIOC, GPIO_PIN_7, on); }

/*
* =============== SR04 ===============
* TRIG -- D11 -- PA7
* ECHO -- D12 -- PA6
*/
static void SHIELD_SR04_Port_Init (void) {
GPIO_InitTypeDef GPIO_InitType;

__HAL_RCC_GPIOA_CLK_ENABLE ();

GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_LOW;
GPIO_InitType.Pin = GPIO_PIN_7;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);

GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
GPIO_InitType.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOA, &GPIO_InitType);
}
void SHIELD_TRIG (uint8_t on) { _DOUTx(GPIOA, GPIO_PIN_7, on); }
uint8_t SHIELD_ECHO (void) { return _DINx (GPIOA, GPIO_PIN_6); }

/*
* ============= 1 Wire UART6 (AF08)===============
* 1W_Tx -- PA11 (OD+PU)
* 1W_Rx -- PA12 (I)
*/
static UART_HandleTypeDef h1w_uart;

/*!
* \brief
* This function handles UART Communication Timeout.
* \param huart: Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* \param Flag: specifies the UART flag to check.
* \param Status: The new Flag status (SET or RESET).
* \param Timeout: Timeout duration
* \return HAL status
*/
static HAL_StatusTypeDef _WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Timeout) {
uint32_t tickstart = HAL_GetTick();

if (Status != RESET) Status = SET; /* Catch wrong Status */

/* Wait until flag is on FlagStatus Status */
while (__HAL_UART_GET_FLAG (huart, Flag) == Status) {
if ((Timeout == 0) || ((HAL_GetTick() - tickstart ) > Timeout)) {
/* Give up */
huart->gState= HAL_UART_STATE_READY; /* Mark Timeout as ready */
__HAL_UNLOCK (huart); /* Process Unlocked */
return HAL_TIMEOUT; /* Return the TIMEOUT */
}
}
return HAL_OK;
}

/*!
* \brief
* Initialize 1-Wire UART to 8bits, no parity, 1 stop, so it can
* be used for 1-Wire communication
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR The Init failed.
*/
static LLD_Status_en _1W_UART_Init (void) {
_1WIRE_UART_CLK_ENABLE (); // Enable 1-wire's USART clock

/*
* USART configured as follows:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - BaudRate = _1WIRE_UART_INIT_BR baud
* - Hardware flow control disabled (RTS and CTS signals)
*/
h1w_uart.Instance = _1WIRE_UART_INSTANCE;
h1w_uart.Init.BaudRate = _1WIRE_UART_INIT_BR;
h1w_uart.Init.WordLength = UART_WORDLENGTH_8B;
h1w_uart.Init.StopBits = UART_STOPBITS_1;
h1w_uart.Init.Parity = UART_PARITY_NONE;
h1w_uart.Init.Mode = UART_MODE_TX_RX;

if (HAL_UART_Init(&h1w_uart) != HAL_OK)
return LLD_ERROR;
return LLD_OK;
}


/*!
* Init the KEY 1wire interface and allocate all resources for it
* \return The status of the operation
* \arg LLD_OK Success
* \arg LLD_ERROR The Init failed.
*/
LLD_Status_en SHIELD_1W_Init (void) {
GPIO_InitTypeDef GPIO_InitStruct;

__HAL_RCC_GPIOA_CLK_ENABLE ();

GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
HAL_GPIO_WritePin (GPIOA, GPIO_InitStruct.Pin, GPIO_PIN_SET);
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_12;
//GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
/*^
* Mark as alternate because HAL_GPIO_Init ()
* can not configure Input + alternate
*/
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

return _1W_UART_Init ();
}

/*!
* \brief
* Set a Baudrate to the UART, to use for 1-Wire communication
* \param br The desired baudrate
* \return The status of the operation (part of toolbox)
* \arg DRV_ERROR Fail
* \arg DRV_READY Success
*/
drv_status_en SHIELD_1W_UART_BR (uint32_t br) {
/*
* Keep USART configured as already set by Init:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - Hardware flow control disabled (RTS and CTS signals)
*/
if (! IS_UART_BAUDRATE (br) )
return DRV_ERROR;
h1w_uart.Init.BaudRate = br;

/* Check the Over Sampling */
if(h1w_uart.Init.OverSampling == UART_OVERSAMPLING_8) {
/*------- UART-associated USART registers setting : BRR Configuration ------*/
if((h1w_uart.Instance == USART1)){
h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
}
else {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING8 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
}
}
else {
/*------- UART-associated USART registers setting : BRR Configuration ------*/
if((h1w_uart.Instance == USART1)) {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK2Freq(), h1w_uart.Init.BaudRate);
}
else {
h1w_uart.Instance->BRR = UART_BRR_SAMPLING16 (HAL_RCC_GetPCLK1Freq(), h1w_uart.Init.BaudRate);
}
}
return DRV_READY;
}

/*!
* \brief
* Read-Write functionality. We use the following USART configuration.
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* \return The byte received. On failure return 0xFFFF (bus released state)
* \note
* Due to the nature of the PCB, the received byte is the actual bus
* condition during the communication frame (time slot)
*/
uint16_t SHIELD_1W_RW (uint8_t byte)
{
if (h1w_uart.Init.WordLength != UART_WORDLENGTH_8B) return (uint8_t)0xFFFF;
if (h1w_uart.Init.Parity != UART_PARITY_NONE) return (uint8_t)0xFFFF;

if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TXE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
return 0x1FF;
WRITE_REG (h1w_uart.Instance->DR, (byte & (uint8_t)0xFF));
if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_TC, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
return 0x2FF;
//if (_WaitOnFlagUntilTimeout (&h1w_uart, UART_FLAG_RXNE, RESET, _1WIRE_UART_TIMEOUT) != HAL_OK)
// return 0xFFFF;
return (uint8_t)(h1w_uart.Instance->DR & (uint8_t)0x00FF);
}

/*!
* \brief
* Receive functionality. We use USART blocking mode.
* \return The byte received. On failure return 0xFF (bus released state)
* \note
* Due to the nature of the PCB, the received byte is the actual bus
* condition during the communication frame (time slot)
*/
uint8_t SHIELD_1W_Rx (void) {
uint8_t rx;
if (HAL_UART_Receive (&h1w_uart, &rx, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
rx = 0xFF;
return rx;
}

/*!
* \brief
* Transmit functionality. We use USART blocking mode.
* \return The status of transition
* \arg 0 Success
* \arg 1 Fail
*/
uint8_t SHIELD_1W_Tx (uint8_t byte) {
if (HAL_UART_Transmit (&h1w_uart, &byte, sizeof (uint8_t), _1WIRE_UART_TIMEOUT) != HAL_OK)
return 1;
return 0;
}

LLD_Status_en SHIELD_Init (void) {
SHIELD_LCD_Port_Init ();
SHIELD_LED_Port_Init ();
SHIELD_BRIDGE_Port_Init ();
SHIELD_SR04_Port_Init ();

SHIELD_1W_Init ();
COM_Init ();
return LLD_OK;
}

/*
* ============= Serial console UART2 (AF07)===============
* COM_Tx -- PA2 (PP)
* COM_Rx -- PA3 (I)
*/
static UART_HandleTypeDef com_huart;
static deque08_t _com_rxq;
static byte_t _com_rxbuffer[COM_BUFFER_SIZE];

/*!
* \brief
* Called from USART IRQ to put the read character to queue
* \param Pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
*
* \return The status of the operation
* \arg HAL_ERROR Fail
* \arg HAL_OK Success
*/
static HAL_StatusTypeDef _UART_read_data (UART_HandleTypeDef *huart, deque08_t *q) {
uint8_t r;

__HAL_LOCK(huart); /*
* We don't try to receive valid data while the USART is
* locked from transmitter. It's OK ;)
*/

/* Receive data based on Word length and parity */
switch (huart->Init.WordLength) {
default:
case UART_WORDLENGTH_8B:
if(huart->Init.Parity == UART_PARITY_NONE)
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
else
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x007F);
break;
case UART_WORDLENGTH_9B:
if(huart->Init.Parity == UART_PARITY_NONE) {
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x01FF);
__HAL_UNLOCK(huart);
return HAL_ERROR;
/* Not supported Configuration */
} else
r = (uint8_t)(huart->Instance->DR & (uint16_t)0x00FF);
break;
}
deque08_push_back (q, r);
/*!<
* \note
* We queue the received bytes. The user application MUST
* read the queue in a regular basis, or else this IRQ will
* find queue full and we will have data loss.
*/

__HAL_UNLOCK(huart);
return HAL_OK;
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
__HAL_UART_CLEAR_PEFLAG (huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_READY;
/*
* Clear all the error flag at once,
* Set USART READY for re-start,
* Error Callback
*/
}
/*!
* \brief
* USART serial handler. Pushes every received character to a queue.
*
* In the IRQ handler there is only Rx functionality provided by this driver.
* The Error handling call the HAL's callback (which are empty)
* The Tx part, is not implemented
*/
void USART2_IRQHandler (void) {
uint32_t tmp_flag = 0, tmp_it_source = 0;

// ======= Error handler =========
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_PE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_PE)) != RESET)) {
/* UART parity error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_PE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_FE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_ERR)) != RESET)) {
/* UART frame error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_FE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_NE)) != RESET) &&
(tmp_it_source != RESET)){
/* UART noise error interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_NE;
}
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_ORE)) != RESET) &&
(tmp_it_source != RESET)){
/* USART Over-Run interrupt occurred */
com_huart.ErrorCode |= HAL_UART_ERROR_ORE;
}

if(com_huart.ErrorCode != HAL_UART_ERROR_NONE) {
HAL_UART_ErrorCallback (&com_huart);
}

// ====== Get Data =========
if(((tmp_flag = __HAL_UART_GET_FLAG(&com_huart, UART_FLAG_RXNE)) != RESET) &&
((tmp_it_source = __HAL_UART_GET_IT_SOURCE(&com_huart, UART_IT_RXNE)) != RESET)) {
// Read byte
_UART_read_data (&com_huart, &_com_rxq); // Don't check return status
}

}

/*!
* \brief
* Initialize the UART and UART IRQ handler
* \return The status of the operation
* \arg LLD_ERROR Fail
* \arg LLD_OK Success
*/
static LLD_Status_en _COM_UART_Init (void) {
/*
* Enable UART clock
*/
_COM_CLK_ENABLE();

deque08_link_buffer (&_com_rxq, _com_rxbuffer);
deque08_set_capacity (&_com_rxq, COM_BUFFER_SIZE);
deque08_init (&_com_rxq);

/*
* USART configured as follows:
* - Word Length = 8 Bits
* - Stop Bit = One Stop bit
* - Parity = No parity
* - BaudRate = COM_BAUDRATE baud
* - Hardware flow control disabled (RTS and CTS signals)
*/
com_huart.Instance = COM_UART_INSTANCE;
com_huart.Init.BaudRate = COM_UART_BAUDRATE;
com_huart.Init.WordLength = UART_WORDLENGTH_8B;
com_huart.Init.StopBits = UART_STOPBITS_1;
com_huart.Init.Parity = UART_PARITY_NONE;
com_huart.Init.Mode = UART_MODE_TX_RX;

if (HAL_UART_Init(&com_huart) != HAL_OK)
return LLD_ERROR;

/*
* Enable IRQ for Rx
* Tx IRQ enabled by COM_transmit ()
*/
HAL_NVIC_SetPriority (COM_UART_IRQ, 0x0D, 0);
HAL_NVIC_EnableIRQ (COM_UART_IRQ);

/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(&com_huart, UART_IT_RXNE);
/* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
//__HAL_UART_ENABLE_IT(&com_huart, UART_IT_ERR);

return LLD_OK;
}


/*!
* Initialize the COM dedicated I/O and allocate resources
* \return The status of the operation
*/
LLD_Status_en COM_Init (void) {
GPIO_InitTypeDef GPIO_InitStruct;

__HAL_RCC_GPIOA_CLK_ENABLE ();

GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
// GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init (GPIOA, &GPIO_InitStruct);

return _COM_UART_Init();
}

/*!
* \brief
* Set UART baudrate
* \param br The desired baudrate
* \return The status of the operation
* \arg LLD_ERROR Fail
* \arg LLD_OK Success
*/
LLD_Status_en COM_baudrate (uint32_t br) {
// Change only the Baudrate
com_huart.Init.BaudRate = br;
if (HAL_UART_Init(&com_huart) != HAL_OK)
return LLD_ERROR;
return LLD_OK;
}

/*!
* \brief
* USART's putchar functionality to link with io system
* This function is compatible with putchar() in "stdio.h"
*/
int COM_putchar (char c) {
if (_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, RESET, COM_UART_PUTCHAR_TIMEOUT) != HAL_OK)
return 0xFFFF;
WRITE_REG (COM_UART_INSTANCE->DR, (c & (uint8_t)0xFF));
/*!<
* \note
* The sequence:
* - Read operation to USART_SR register [USART_GetFlagStatus()]
* - Write operation to USART_DR register [USART_SendData()]
* clears the TC Flag
*
* The TXE Flag is cleared by the write operation to USART_DR register
* [USART_SendData()]
*/
return (int)c;
}

/*!
* \brief
* USART's getchar functionality to link with io system
* This function is compatible with getchar() in "stdio.h"
*/
int COM_getchar (void) {
clock_t mark = clock ();
clock_t to = COM_UART_GETCHAR_TIMEOUT*get_freq();
clock_t now;
byte_t r=0;

while (deque08_pop_front (&_com_rxq, &r) == 0) {
now = clock ();
if (_CLOCK_DIFF(now, mark) >= to)
return 0;
}
return r;
}

/*!
* \brief
* Transmit functionality to link with io system
* This function is compatible with htp tx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of bytes to transmit
*/
int COM_Transmit (uint8_t *data, int size) {
int r = size;

while (size--) {
//queue08_push (&_com_txq, (byte_t)*data);
COM_putchar(*data++);
}
_WaitOnFlagUntilTimeout (&com_huart, UART_FLAG_TC, SET, COM_UART_PUTCHAR_TIMEOUT);
return r;
}

/*!
* \brief
* Check receive functionality synchronized to IRQ
* This function is compatible with htp rx functionality
*
* \return The number of bytes on queue (<package_size> indicates done)
*/
int COM_CheckReceive (void) {
return deque08_size (&_com_rxq);
}

/*!
* \brief
* Receive flush functionality to link with io system
* This function is compatible with htp rx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of received bytes
*/
void COM_ReceiveFlush (void) {
deque08_flush (&_com_rxq);
}

/*!
* \brief
* Receive functionality to link with io system
* This function is compatible with htp rx functionality
*
* \param data Pointer to data buffer
* \param size Size of buffer (number of bytes)
* \return The number of received bytes
*/
int COM_Receive (uint8_t *data, int size) {
int i;
uint8_t r=1, b;

for (i=0 ; r !=0 && i<size ; ++i) {
r = deque08_pop_front (&_com_rxq, &b);
data[i] = b;
}
return i;
}

+ 124
- 0
assignment_3/Libraries/drivers/thermostat_shield.h View File

@@ -0,0 +1,124 @@
/*!
* \file
* thermostat_shield.h
* \brief
* Nucleo thermostat shield port file. This file contain the implementation of driver
* calls for the shield.
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/

#ifndef DRIVERS_THERMOSTAT_SHIELD_H_
#define DRIVERS_THERMOSTAT_SHIELD_H_

#include "NUCLEO_F401RE.h"
#include "driver_types.h"
#include "deque08.h"

/*
* =============== Digital I/O ===============
*/

/*
* =============== LCD ===============
* LCD_BD4 -- D8 -- PA9
* LCD_BD5 -- D7 -- PA8
* LCD_BD6 -- D6 -- PB10
* LCD_BD7 -- D5 -- PB4
* LCD_RS -- D15 -- PB8
* LCD_EN -- D14 -- PB9
* LCD_BL -- D2 -- PA10
*/
void SHIELD_LCD_DB4 (uint8_t en);
void SHIELD_LCD_DB5 (uint8_t en);
void SHIELD_LCD_DB6 (uint8_t en);
void SHIELD_LCD_DB7 (uint8_t en);
void SHIELD_LCD_RS (uint8_t en);
void SHIELD_LCD_EN (uint8_t en);
void SHIELD_LCD_BL (uint8_t en);

/*
* =============== LED ===============
* LED0 -- D4 -- PB5
* LED1 -- D3 -- PB3
*/
void SHIELD_LED0 (uint8_t on);
void SHIELD_LED1 (uint8_t on);

#define LED_RED SHIELD_LED0
#define LED_GREEN SHIELD_LED1

/*
* =============== BRIDGE ===============
* BR1 -- D10 -- PB6
* BR2 -- D9 -- PC7
*/
void SHIELD_BR1 (uint8_t on);
void SHIELD_BR2 (uint8_t on);


/*
* =============== SR04 ===============
* TRIG -- D11 -- PA7
* ECHO -- D12 -- PA6
*/
void SHIELD_TRIG (uint8_t on);
uint8_t SHIELD_ECHO (void);

/*
* ============= 1 Wire USART6 (AF08)===============
* 1W_Tx -- PA11 (OD+PU)
* 1W_Rx -- PA12 (I)
*/
// non-shared resources
#define _1WIRE_UART_INSTANCE (USART6)
#define _1WIRE_UART_INIT_BR (9600)
#define _1WIRE_UART_TIMEOUT (10) /*!< 10msec is good enough */
/*!
* Helper Macros linked to USART used
*/
#define _1WIRE_UART_CLK_ENABLE __HAL_RCC_USART6_CLK_ENABLE
#define _1WIRE_UART_CLK_DISABLE __HAL_RCC_USART6_CLK_DISABLE

LLD_Status_en SHIELD_1W_Init (void);

drv_status_en SHIELD_1W_UART_BR (uint32_t br);
uint16_t SHIELD_1W_RW (uint8_t byte);
uint8_t SHIELD_1W_Rx (void);
uint8_t SHIELD_1W_Tx (uint8_t byte);

LLD_Status_en SHIELD_Init (void);


/*
* ============= Serial console UART2 (AF07)===============
* COM_Tx -- PA2 (PP)
* COM_Rx -- PA3 (I)
*/
#define COM_UART_INSTANCE USART2
#define COM_UART_IRQ USART2_IRQn
#define COM_UART_BAUDRATE (57600)
#define COM_UART_GETCHAR_TIMEOUT (5) // 5sec
#define COM_UART_PUTCHAR_TIMEOUT (10) // 1 [CPU time]

#define COM_BUFFER_SIZE (256)

/*!
* Helper Macros linked to USART used
*/
#define _COM_CLK_ENABLE __HAL_RCC_USART2_CLK_ENABLE
#define _COM_CLK_DISNABLE __HAL_RCC_USART2_CLK_DISABLE


LLD_Status_en COM_Init (void);
LLD_Status_en COM_baudrate (uint32_t br);
int COM_putchar (char c);
int COM_getchar (void);
int COM_Transmit (uint8_t *data, int size);
int COM_CheckReceive (void);
void COM_ReceiveFlush (void);
int COM_Receive (uint8_t *data, int size);


#endif /* DRIVERS_THERMOSTAT_SHIELD_H_ */

+ 130
- 0
assignment_3/src/console.c View File

@@ -0,0 +1,130 @@
/*
* console.c
*
* Created on: Jun 28, 2020
* Author: hoo2
*/

#include "console.h"

static char _buffer[COM_BUFFER_SIZE];
static int _cursor;

static char _ans[512];

void parse (char* buffer) {
int i;
float_t s;

if ((strncmp((const void*)buffer, "help", 4) == 0) ||
(strncmp((const void*)buffer, "?", 1) == 0) ) {
i = sprintf (_ans, "\r\nThermostat commands:\r\n");
i += sprintf (&_ans[i], "info : Get information\r\n");
i += sprintf (&_ans[i], "set Tset <val> : Set Thermostat\'s temperature\r\n");
i += sprintf (&_ans[i], "set Thyst <val> : Set Thermostat\'s hysteresis\r\n");
i += sprintf (&_ans[i], "set Pset <val> : Set Proximity\r\n");
i += sprintf (&_ans[i], "set Physt <val> : Set Proximity\'s hysteresis\r\n");
i += sprintf (&_ans[i], "set mode heating : Set Thermostat to heating mode\r\n");
i += sprintf (&_ans[i], "set mode cooling : Set Thermostat to cooling mode\r\n");
i += sprintf (&_ans[i], "\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)buffer, "info", 4) == 0) {
i = sprintf (_ans, "\r\nThermostat data:\r\n");
i += sprintf (&_ans[i], "Tcur = %4.1f\r\n", temp_get_current ());
i += sprintf (&_ans[i], "Tav = %4.1f\r\n", app_data.Tav);
i += sprintf (&_ans[i], "Mode = %s\r\n", (settings.mode == HEATING) ? "Heating" : "Cooling");
i += sprintf (&_ans[i], "Output = %s\r\n", (app_data.flag_output) ? "On" : "Off");
i += sprintf (&_ans[i], "Tset = %4.1f, Hyst = %4.1f\r\n", settings.Tset, settings.Thyst);
i += sprintf (&_ans[i], "Pset = %4.1f, Hyst = %4.1f\r\n", settings.Pset, settings.Physt);
i += sprintf (&_ans[i], "\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)buffer, "set ", 4) == 0) {
if (strncmp((const void*)&buffer[4], "Tset ", 5) == 0) {
sscanf((const void*)&buffer[9], "%f", &s);
if (s > -20 && s < 80) {
settings.Tset = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Thyst ", 6) == 0) {
sscanf((const void*)&buffer[10], "%f", &s);
if (s > 0 && s < 20) {
settings.Thyst = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Pset ", 5) == 0) {
sscanf((const void*)&buffer[9], "%f", &s);
if (s > 0 && s < 100)
settings.Pset = s;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "Physt ", 6) == 0) {
sscanf((const void*)&buffer[10], "%f", &s);
if (s > 0 && s < 50) {
settings.Physt = s;
i = sprintf (_ans, "OK\r\n");
}
else
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[4], "mode ", 5) == 0) {
if (strncmp((const void*)&buffer[9], "heating", 7) == 0) {
settings.mode = HEATING;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
else if (strncmp((const void*)&buffer[9], "cooling", 7) == 0) {
settings.mode = COOLING;
i = sprintf (_ans, "OK\r\n");
_ans[i] =0;
}
}
else {
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
}
else {
i = sprintf (_ans, "Error\r\n");
_ans[i] =0;
}
COM_Transmit((uint8_t*)_ans, i);
}

void console (void) {
int ch;

if (COM_CheckReceive()) {
ch = COM_getchar(); // get character
COM_putchar((char)ch); // Echo back
_buffer[_cursor++] = ch; // store

// Backspace, delete
if (ch == 0x08 || ch == 0x7F)
--_cursor;

if (ch == 0 || ch == '\n' || ch == '\r') {
COM_putchar('\n'); // Echo an extra '\n'
_buffer[_cursor -1] = 0;
_cursor =0;
parse(_buffer);
}
if (_cursor >= COM_BUFFER_SIZE) {
_buffer[_cursor -1] = 0;
_cursor =0;
parse(_buffer);
}
}
}


+ 19
- 0
assignment_3/src/console.h View File

@@ -0,0 +1,19 @@
/*
* console.h
*
* Created on: Jun 28, 2020
* Author: hoo2
*/

#ifndef CONSOLE_H_
#define CONSOLE_H_

#include <hal.h>
#include "thermostat.h"
#include <string.h>

extern float_t temp_get_current (void);

void console (void);

#endif /* CONSOLE_H_ */

+ 187
- 0
assignment_3/src/main.c View File

@@ -0,0 +1,187 @@
/*!
* \file
* main.c
* \brief
* Main application file
*
* Author: Christos Choutouridis AEM: 8997
* email : <cchoutou@ece.auth.gr>
*/
#include <hal.h>
#include "thermostat.h"
#include "console.h"
/*
* Zero initialized globals
*/
app_data_t app_data;
state_en state;
// Value initialized globals
settings_t _Init_settings(settings);
/*
* helper api
*/
float_t temp_get_current (void) {
return (app_data.cur) ? app_data.T[app_data.cur-1] : app_data.T[MEASUREMENTS-1];
}
void control (void) {
static time_t sample =0;
time_t now = time(0); // get time
// Proximity
if (proximity(&prox) < settings.Pset)
app_data.flag_proximity = 1;
else if (proximity(&prox) < settings.Pset + settings.Physt)
;
else
app_data.flag_proximity = 0;
// Temperature calculation
if (now - sample >= MEAS_INTERVAL) {
sample = now;
app_data.T[app_data.cur] = temp_read();
if (++app_data.cur >= MEASUREMENTS) {
app_data.cur =0;
float_t f =0;
for (int i=0 ; i<MEASUREMENTS ; ++i) {
f += app_data.T[i];
}
app_data.Tav = f / MEASUREMENTS;
app_data.signal_cycle = 1;
app_data.flag_init = 0;
}
}
// Output handling
if (!app_data.flag_init) {
switch (settings.mode) {
case HEATING: {
if (app_data.Tav <= settings.Tset)
app_data.flag_output = 1;
else if (app_data.Tav < settings.Tset + settings.Thyst)
;
else
app_data.flag_output = 0;
}
break;
case COOLING: {
if (app_data.Tav <= settings.Tset - settings.Thyst)
app_data.flag_output = 0;
else if (app_data.Tav < settings.Tset)
;
else
app_data.flag_output = 1;
}
break;
}
}
}
void display (void) {
static time_t mark =0;
char line1[18];
char line2[18];
time_t now = time(0);
switch (state) {
case ST_INIT:
sprintf(line1, "\fInitializing %c ", (time(0)%2) ? '*' : ' ');
sprintf(line2, "\n ");
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (app_data.signal_cycle) {
app_data.signal_cycle =0;
mark = now;
state = ST_AVERAGE;
}
break;
case ST_COUNT:
sprintf(line1, "\fMeasuring %c ", (time(0)%2) ? '*' : ' ');
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (app_data.signal_cycle) {
app_data.signal_cycle =0;
mark = now;
state = ST_AVERAGE;
}
break;
case ST_AVERAGE:
sprintf(line1, "\fTav=%4.1f ", app_data.Tav);
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (app_data.flag_proximity)
state = ST_USER;
else if (now - mark >= UI_AVERAGE_TIME)
state = ST_COUNT;
break;
case ST_USER:
sprintf(line1, "\fTav=%4.1f T=%4.1f", app_data.Tav, temp_get_current());
sprintf(line2, "\n%s: %s ",
(settings.mode == HEATING) ? "Heating" : "Cooling",
(app_data.flag_output) ? "On " : "Off"
);
// escapes
if (!app_data.flag_proximity)
state = ST_COUNT;
break;
}
lcd_puts(line1);
lcd_puts(line2);
}
void outputs (void) {
static uint8_t pr_output =0;
if (app_data.flag_init)
return;
led_green(app_data.flag_output && settings.mode == COOLING);
led_red (app_data.flag_output && settings.mode == HEATING);
if (app_data.flag_output != pr_output) {
relay(app_data.flag_output);
pr_output = app_data.flag_output;
}
}
int main(void) {
hal_hw_init ();
lcd_init ();
proximity_init(&prox);
temp_init (TEMP_11_BIT);
lcd_enable(1);
app_data.flag_init = 1;
while (1) {
control ();
display ();
outputs();
console ();
HAL_Delay(10);
}
}

+ 65
- 0
assignment_3/src/thermostat.h View File

@@ -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_ */

Loading…
Cancel
Save