368 lines
9.4 KiB
C
368 lines
9.4 KiB
C
/*
|
|
* \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
|
|
}
|
|
}
|