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