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