314 lines
7.7 KiB
C
314 lines
7.7 KiB
C
/*!
|
|
* \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;
|
|
}
|