mirror of
https://github.com/apache/nuttx.git
synced 2026-10-24 07:18:45 +00:00
tickless
This commit is contained in:
parent
b91fbed6a6
commit
3a4b0e12a1
3 changed files with 671 additions and 114 deletions
|
|
@ -96,6 +96,8 @@ CHIP_CSRCS += lpc43_start.c lpc43_uart.c
|
|||
|
||||
ifneq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CHIP_CSRCS += lpc43_timerisr.c
|
||||
else
|
||||
CHIP_CSRCS += lpc43_tickless_rit.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BUILD_PROTECTED),y)
|
||||
|
|
|
|||
|
|
@ -162,8 +162,12 @@ static const struct spi_ops_s g_spi0ops =
|
|||
.cmddata = lpc43_ssp0cmddata, /* Provided externally */
|
||||
#endif
|
||||
.send = ssp_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = ssp_exchange,
|
||||
#else
|
||||
.sndblock = ssp_sndblock,
|
||||
.recvblock = ssp_recvblock,
|
||||
#endif
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = lpc43_ssp0register, /* Provided externally */
|
||||
#else
|
||||
|
|
@ -197,8 +201,12 @@ static const struct spi_ops_s g_spi1ops =
|
|||
.cmddata = lpc43_ssp1cmddata, /* Provided externally */
|
||||
#endif
|
||||
.send = ssp_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = ssp_exchange,
|
||||
#else
|
||||
.sndblock = ssp_sndblock,
|
||||
.recvblock = ssp_recvblock,
|
||||
#endif
|
||||
#ifdef CONFIG_SPI_CALLBACK
|
||||
.registercallback = lpc43_ssp1register, /* Provided externally */
|
||||
#else
|
||||
|
|
@ -526,6 +534,76 @@ static uint16_t ssp_send(FAR struct spi_dev_s *dev, uint16_t wd)
|
|||
return (uint16_t)regval;
|
||||
}
|
||||
|
||||
static void ssp_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
|
||||
FAR void *rxbuffer, size_t nwords) {
|
||||
FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev;
|
||||
union
|
||||
{
|
||||
FAR uint8_t *p8;
|
||||
FAR uint16_t *p16;
|
||||
FAR void *pv;
|
||||
} tx;
|
||||
union
|
||||
{
|
||||
FAR uint8_t *p8;
|
||||
FAR uint16_t *p16;
|
||||
FAR void *pv;
|
||||
} rx;
|
||||
uint32_t data;
|
||||
uint32_t datadummy = (priv->nbits > 8)?0xffff:0xff;
|
||||
uint32_t rxpending = 0;
|
||||
|
||||
/* While there is remaining to be sent (and no synchronization error has occurred) */
|
||||
|
||||
sspdbg("nwords: %d\n", nwords);
|
||||
|
||||
tx.pv = txbuffer;
|
||||
rx.pv = rxbuffer;
|
||||
|
||||
while (nwords || rxpending)
|
||||
{
|
||||
/* Write data to the data register while (1) the TX FIFO is
|
||||
* not full, (2) we have not exceeded the depth of the TX FIFO,
|
||||
* and (3) there are more bytes to be sent.
|
||||
*/
|
||||
|
||||
spivdbg("TX: rxpending: %d nwords: %d\n", rxpending, nwords);
|
||||
while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) &&
|
||||
(rxpending < LPC43_SSP_FIFOSZ) && nwords)
|
||||
{
|
||||
if (txbuffer && priv->nbits > 8)
|
||||
{
|
||||
data = (uint32_t)*tx.p16++;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (uint32_t)*tx.p8++;
|
||||
}
|
||||
|
||||
ssp_putreg(priv, LPC43_SSP_DR_OFFSET, txbuffer?data:datadummy);
|
||||
nwords--;
|
||||
rxpending++;
|
||||
}
|
||||
|
||||
/* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */
|
||||
|
||||
spivdbg("RX: rxpending: %d\n", rxpending);
|
||||
while (ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_RNE)
|
||||
{
|
||||
data = ssp_getreg(priv, LPC43_SSP_DR_OFFSET);
|
||||
if (rxbuffer && priv->nbits > 8)
|
||||
{
|
||||
*rx.p16++ = (uint16_t)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
*rx.p8++ = (uint8_t)data;
|
||||
}
|
||||
rxpending--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ssp_sndblock
|
||||
*
|
||||
|
|
@ -547,72 +625,7 @@ static uint16_t ssp_send(FAR struct spi_dev_s *dev, uint16_t wd)
|
|||
|
||||
static void ssp_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords)
|
||||
{
|
||||
FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev;
|
||||
union
|
||||
{
|
||||
FAR const uint8_t *p8;
|
||||
FAR const uint16_t *p16;
|
||||
FAR const void *pv;
|
||||
} u;
|
||||
uint32_t data;
|
||||
uint32_t sr;
|
||||
|
||||
/* Loop while thre are bytes remaining to be sent */
|
||||
|
||||
sspdbg("nwords: %d\n", nwords);
|
||||
u.pv = buffer;
|
||||
while (nwords > 0)
|
||||
{
|
||||
/* While the TX FIFO is not full and there are bytes left to send */
|
||||
|
||||
while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) && nwords)
|
||||
{
|
||||
/* Fetch the data to send */
|
||||
|
||||
if (priv->nbits > 8)
|
||||
{
|
||||
data = (uint32_t)*u.p16++;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (uint32_t)*u.p8++;
|
||||
}
|
||||
|
||||
/* Send the data */
|
||||
|
||||
ssp_putreg(priv, LPC43_SSP_DR_OFFSET, data);
|
||||
nwords--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Then discard all card responses until the RX & TX FIFOs are emptied. */
|
||||
|
||||
sspdbg("discarding\n");
|
||||
do
|
||||
{
|
||||
/* Is there anything in the RX fifo? */
|
||||
|
||||
sr = ssp_getreg(priv, LPC43_SSP_SR_OFFSET);
|
||||
if ((sr & SSP_SR_RNE) != 0)
|
||||
{
|
||||
/* Yes.. Read and discard */
|
||||
|
||||
(void)ssp_getreg(priv, LPC43_SSP_DR_OFFSET);
|
||||
}
|
||||
|
||||
/* There is a race condition where TFE may go true just before
|
||||
* RNE goes true and this loop terminates prematurely. The nasty little
|
||||
* delay in the following solves that (it could probably be tuned
|
||||
* to improve performance).
|
||||
*/
|
||||
|
||||
else if ((sr & SSP_SR_TFE) != 0)
|
||||
{
|
||||
up_udelay(100);
|
||||
sr = ssp_getreg(priv, LPC43_SSP_SR_OFFSET);
|
||||
}
|
||||
}
|
||||
while ((sr & SSP_SR_RNE) != 0 || (sr & SSP_SR_TFE) == 0);
|
||||
return ssp_exchange(dev, buffer, NULL, nwords);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -636,54 +649,7 @@ static void ssp_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size
|
|||
|
||||
static void ssp_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords)
|
||||
{
|
||||
FAR struct lpc43_sspdev_s *priv = (FAR struct lpc43_sspdev_s *)dev;
|
||||
union
|
||||
{
|
||||
FAR uint8_t *p8;
|
||||
FAR uint16_t *p16;
|
||||
FAR void *pv;
|
||||
} u;
|
||||
uint32_t data;
|
||||
uint32_t rxpending = 0;
|
||||
|
||||
/* While there is remaining to be sent (and no synchronization error has occurred) */
|
||||
|
||||
sspdbg("nwords: %d\n", nwords);
|
||||
u.pv = buffer;
|
||||
while (nwords || rxpending)
|
||||
{
|
||||
/* Fill the transmit FIFO with 0xffff...
|
||||
* Write 0xff to the data register while (1) the TX FIFO is
|
||||
* not full, (2) we have not exceeded the depth of the TX FIFO,
|
||||
* and (3) there are more bytes to be sent.
|
||||
*/
|
||||
|
||||
spivdbg("TX: rxpending: %d nwords: %d\n", rxpending, nwords);
|
||||
while ((ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_TNF) &&
|
||||
(rxpending < LPC43_SSP_FIFOSZ) && nwords)
|
||||
{
|
||||
ssp_putreg(priv, LPC43_SSP_DR_OFFSET, 0xffff);
|
||||
nwords--;
|
||||
rxpending++;
|
||||
}
|
||||
|
||||
/* Now, read the RX data from the RX FIFO while the RX FIFO is not empty */
|
||||
|
||||
spivdbg("RX: rxpending: %d\n", rxpending);
|
||||
while (ssp_getreg(priv, LPC43_SSP_SR_OFFSET) & SSP_SR_RNE)
|
||||
{
|
||||
data = (uint8_t)ssp_getreg(priv, LPC43_SSP_DR_OFFSET);
|
||||
if (priv->nbits > 8)
|
||||
{
|
||||
*u.p16++ = (uint16_t)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
*u.p8++ = (uint8_t)data;
|
||||
}
|
||||
rxpending--;
|
||||
}
|
||||
}
|
||||
return ssp_exchange(dev, NULL, buffer, nwords);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
589
arch/arm/src/lpc43xx/lpc43_tickless_rit.c
Normal file
589
arch/arm/src/lpc43xx/lpc43_tickless_rit.c
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/lpc43/lpc43_rit.c
|
||||
*
|
||||
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <arch/board/board.h>
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "arch.h"
|
||||
#include "time.h"
|
||||
#include "chip/lpc43_rit.h"
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define LPC43_TL_NANOS_IN_SEC 1000000000
|
||||
|
||||
#define LPC43_TL_NANOS_IN_TICK LPC43_TL_NANOS_IN_SEC/LPC43_CCLK
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t to_reset = UINT32_MAX / 2;
|
||||
static uint32_t to_reset_next = to_reset + UINT32_MAX / 4;
|
||||
static uint32_t to_end = to_reset_next + UINT32_MAX / 8;
|
||||
|
||||
static uint32_t reset_ticks = 1000; /* ticks to add to force a reset */
|
||||
|
||||
static uint64_t base = 0; /* time base */
|
||||
|
||||
static uint64_t alarm_time = 0; /* alarmTime to set on next interrupt, used if not already armed */
|
||||
static bool call = false; /* true if callback should be called on next interrupt */
|
||||
static bool armed = false; /* true if alarm is armed for next match */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* some timer HW functions */
|
||||
|
||||
static inline void lpc43_tl_set_counter (uint32_t value)
|
||||
{
|
||||
putreg32 (value, LPC43_RIT_COUNTER);
|
||||
}
|
||||
|
||||
static inline uint32_t lpc43_tl_get_counter (void)
|
||||
{
|
||||
return getreg32 (LPC43_RIT_COUNTER);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_set_compare (uint32_t value)
|
||||
{
|
||||
putreg32 (value, LPC43_RIT_COMPVAL);
|
||||
}
|
||||
|
||||
static inline uint32_t lpc43_tl_get_compare (void)
|
||||
{
|
||||
return getreg32 (LPC43_RIT_COMPVAL);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_set_mask (uint32_t value)
|
||||
{
|
||||
putreg32 (value, LPC43_RIT_MASK);
|
||||
}
|
||||
|
||||
static inline uint32_t lpc43_tl_get_mask (void)
|
||||
{
|
||||
return getreg32 (LPC43_RIT_MASK);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_set_ctrl_bit (uint32_t bit, bool value)
|
||||
{
|
||||
uint32_t regval;
|
||||
regval = getreg32 (LPC43_RIT_CTRL);
|
||||
if (value)
|
||||
{
|
||||
regval |= bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
regval &= ~bit;
|
||||
}
|
||||
putreg32 (regval, LPC43_RIT_CTRL);
|
||||
}
|
||||
|
||||
static inline bool lpc43_tl_get_ctrl_bit (uint32_t bit)
|
||||
{
|
||||
uint32_t regval;
|
||||
regval = getreg32 (LPC43_RIT_CTRL);
|
||||
regval |= bit;
|
||||
if (regval)
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_set_reset_on_match (bool value)
|
||||
{
|
||||
lpc43_tl_set_ctrl_bit (RIT_CTRL_ENCLR, value);
|
||||
}
|
||||
|
||||
static inline bool lpc43_tl_get_reset_on_match (void)
|
||||
{
|
||||
return lpc43_tl_get_ctrl_bit (RIT_CTRL_ENCLR);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_set_enable (bool value)
|
||||
{
|
||||
lpc43_tl_set_ctrl_bit (RIT_CTRL_EN, value);
|
||||
}
|
||||
|
||||
static inline bool lpc43_tl_get_enable (void)
|
||||
{
|
||||
return lpc43_tl_get_ctrl_bit (RIT_CTRL_EN);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_clear_interrupt ()
|
||||
{
|
||||
lpc43_tl_set_ctrl_bit (RIT_CTRL_EN, true);
|
||||
}
|
||||
|
||||
static inline bool lpc43_tl_get_interrupt (void)
|
||||
{
|
||||
return lpc43_tl_get_ctrl_bit (RIT_CTRL_INT);
|
||||
}
|
||||
|
||||
/* converters */
|
||||
|
||||
static inline uint64_t lpc43_tl_ts2tick ( FAR struct timespec *ts)
|
||||
{
|
||||
return ((ts->tv_nsec + ts->tv_sec * LPC43_TL_NANOS_IN_SEC) / LPC43_TL_NANOS_IN_TICK);
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_tick2ts (uint64_t tick, FAR struct timespec *ts)
|
||||
{
|
||||
uint64_t nanos = tick * LPC43_TL_NANOS_IN_TICK;
|
||||
|
||||
ts->tv_sec = nanos / LPC43_TL_NANOS_IN_SEC;
|
||||
ts->tv_nsec = nanos % LPC43_TL_NANOS_IN_SEC;
|
||||
}
|
||||
|
||||
/* logic functions */
|
||||
|
||||
/* force interrupt, no reset possible */
|
||||
|
||||
static void lpc43_tl_force_int ()
|
||||
{
|
||||
lpc43_tl_set_reset_on_match (false);
|
||||
lpc43_tl_set_mask (UINT32_MAX);
|
||||
}
|
||||
|
||||
/* init all vars */
|
||||
|
||||
static void lpc43_tl_init_timer_vars ()
|
||||
{
|
||||
alarm_time = 0;
|
||||
call = false;
|
||||
armed = false;
|
||||
}
|
||||
|
||||
/* calc reset_ticks and set compare to to_reset */
|
||||
|
||||
static void lpc43_tl_calibrate_init ()
|
||||
{
|
||||
uint32_t counter = lpc43_tl_get_counter ();
|
||||
|
||||
uint32_t counter_after = lpc43_tl_get_counter ();
|
||||
counter_after = to_reset + counter;
|
||||
counter_after = counter_after - counter;
|
||||
|
||||
/*shift to toReset*/
|
||||
|
||||
lpc43_tl_set_compare (counter_after);
|
||||
|
||||
counter_after = lpc43_tl_get_counter ();
|
||||
|
||||
reset_ticks = (counter_after - counter) * 2;
|
||||
|
||||
}
|
||||
|
||||
/* process current and set timer in default state */
|
||||
|
||||
static void lpc43_tl_save_timer ()
|
||||
{
|
||||
|
||||
/*process reset if any*/
|
||||
|
||||
uint32_t match = lpc43_tl_get_compare ();
|
||||
|
||||
/*move to end, no resets during processing*/
|
||||
|
||||
lpc43_tl_set_compare (UINT32_MAX);
|
||||
lpc43_tl_set_mask (0);
|
||||
|
||||
if (lpc43_tl_get_interrupt ())
|
||||
{
|
||||
if (lpc43_tl_get_reset_on_match ()) /*was reset ?*/
|
||||
{
|
||||
base = base + match;
|
||||
lpc43_tl_set_reset_on_match (false);
|
||||
}
|
||||
lpc43_tl_clear_interrupt ();
|
||||
}
|
||||
}
|
||||
|
||||
/* assuming safe state, true if set, false - time is in the past */
|
||||
|
||||
static bool lpc43_tl_set_safe_compare (uint32_t time)
|
||||
{
|
||||
if (time < to_reset)
|
||||
{
|
||||
lpc43_tl_set_reset_on_match (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
lpc43_tl_set_reset_on_match (true);
|
||||
}
|
||||
|
||||
lpc43_tl_set_compare (time);
|
||||
|
||||
//check if ok
|
||||
bool reset = lpc43_tl_get_interrupt ();
|
||||
uint32_t counter = lpc43_tl_get_counter ();
|
||||
bool reset_after = lpc43_tl_get_interrupt ();
|
||||
|
||||
if (reset != reset_after)
|
||||
{
|
||||
//was a reset get new counter
|
||||
counter = lpc43_tl_get_counter ();
|
||||
}
|
||||
|
||||
if (reset_after || (!reset_after && time > counter))
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* set_safe_compare in loop */
|
||||
|
||||
static void lpc43_tl_looped_forced_set_compare ()
|
||||
{
|
||||
uint32_t i = 1;
|
||||
bool result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks); /* like in calibrateInit */
|
||||
while (!result)
|
||||
{
|
||||
i++;
|
||||
result = lpc43_tl_set_safe_compare (lpc43_tl_get_counter () + reset_ticks * i);
|
||||
};
|
||||
}
|
||||
|
||||
/* assuming safe state, true if set, false - time is in the past */
|
||||
|
||||
static bool lpc43_tl_set_calc_arm (uint32_t curr, uint32_t to_set, bool arm)
|
||||
{
|
||||
|
||||
uint32_t calcTime;
|
||||
|
||||
if (curr < to_reset_next)
|
||||
{
|
||||
calcTime = min (to_reset_next, to_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curr < to_end)
|
||||
{
|
||||
calcTime = min (lpc43_tl_get_counter () + reset_ticks, to_set);
|
||||
}
|
||||
else
|
||||
{
|
||||
lpc43_tl_looped_forced_set_compare ();
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
|
||||
bool set = lpc43_tl_set_safe_compare (calcTime);
|
||||
|
||||
if (arm && set && (calcTime == to_set))
|
||||
{
|
||||
armed = true;
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/* try to set compare for normal operation */
|
||||
|
||||
static void lpc43_tl_set_default_compare ()
|
||||
{
|
||||
bool result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false);
|
||||
if (!result)
|
||||
{
|
||||
result = lpc43_tl_set_calc_arm (lpc43_tl_get_counter (), UINT32_MAX, false);
|
||||
if (!result)
|
||||
{
|
||||
lpc43_tl_looped_forced_set_compare ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline void lpc43_tl_alarm()
|
||||
{
|
||||
lpc43_tl_init_timer_vars ();
|
||||
lpc43_tl_set_default_compare ();
|
||||
|
||||
struct timespec ts;
|
||||
|
||||
up_timer_gettime(&ts);
|
||||
|
||||
sched_alarm_expiration(&ts);
|
||||
}
|
||||
|
||||
/* interrupt handler */
|
||||
|
||||
static int lpc43_tl_isr (int irq, FAR void *context)
|
||||
{
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
if (call)
|
||||
{
|
||||
/* forced call case */
|
||||
lpc43_tl_set_mask (false);
|
||||
|
||||
lpc43_tl_clear_interrupt ();
|
||||
|
||||
lpc43_tl_alarm();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
lpc43_tl_save_timer ();
|
||||
|
||||
if (armed)
|
||||
{
|
||||
lpc43_tl_alarm();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alarm_time > 0)
|
||||
{
|
||||
uint64_t toSet = alarm_time - base;
|
||||
uint32_t curr = lpc43_tl_get_counter ();
|
||||
|
||||
if (toSet > curr)
|
||||
{
|
||||
if (toSet > to_end)
|
||||
{
|
||||
lpc43_tl_set_default_compare ();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool set = lpc43_tl_set_calc_arm (curr, toSet, true);
|
||||
if (!set)
|
||||
{
|
||||
lpc43_tl_alarm();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lpc43_tl_alarm();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lpc43_tl_set_default_compare ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
irqrestore (flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void up_timer_initialize (void)
|
||||
{
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
lpc43_tl_set_enable (false);
|
||||
|
||||
lpc43_tl_set_compare (UINT32_MAX);
|
||||
lpc43_tl_set_counter (0);
|
||||
lpc43_tl_set_mask (0);
|
||||
|
||||
lpc43_tl_set_reset_on_match (false);
|
||||
lpc43_tl_clear_interrupt ();
|
||||
|
||||
irq_attach (LPC43M4_IRQ_RITIMER, lpc43_tl_isr);
|
||||
up_enable_irq (LPC43M4_IRQ_RITIMER);
|
||||
|
||||
lpc43_tl_init_timer_vars ();
|
||||
|
||||
lpc43_tl_set_enable (true);
|
||||
|
||||
lpc43_tl_calibrate_init ();
|
||||
|
||||
irqrestore (flags);
|
||||
}
|
||||
|
||||
int up_timer_gettime (FAR struct timespec *ts)
|
||||
{
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
uint32_t time;
|
||||
/* no reg changes, only processing */
|
||||
|
||||
/* order of calls is important, reset can come during processing */
|
||||
|
||||
bool reset = lpc43_tl_get_interrupt ();
|
||||
uint32_t count = lpc43_tl_get_counter ();
|
||||
|
||||
/* not processed reset can exist */
|
||||
if (lpc43_tl_get_reset_on_match ())
|
||||
{
|
||||
bool resetAfter = lpc43_tl_get_interrupt ();
|
||||
|
||||
if (reset != resetAfter) /* was a reset get new counter */
|
||||
{
|
||||
count = lpc43_tl_get_counter ();
|
||||
}
|
||||
|
||||
if (resetAfter)
|
||||
{
|
||||
time = base + count + lpc43_tl_get_compare ();
|
||||
}
|
||||
else
|
||||
{
|
||||
time = base + count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
time = base + count;
|
||||
}
|
||||
|
||||
lpc43_tl_tick2ts (time, ts);
|
||||
|
||||
irqrestore (flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
# ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||
int up_alarm_cancel (FAR struct timespec *ts)
|
||||
{
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
/*no reg changes, only variables logic*/
|
||||
|
||||
up_timer_gettime (ts);
|
||||
|
||||
/* let default setup will be done in interrupt handler or setAlarm */
|
||||
lpc43_tl_init_timer_vars ();
|
||||
|
||||
irqrestore (flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int up_alarm_start (FAR const struct timespec *ts)
|
||||
{
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
lpc43_tl_init_timer_vars ();
|
||||
|
||||
lpc43_tl_save_timer ();
|
||||
|
||||
//----calc time to set
|
||||
|
||||
uint64_t time = lpc43_tl_ts2tick (ts);
|
||||
uint64_t toSet = time - base;
|
||||
uint32_t curr = lpc43_tl_get_counter ();
|
||||
|
||||
if (toSet > curr)
|
||||
{
|
||||
alarm_time = time;
|
||||
|
||||
if (toSet > to_end) /* future set */
|
||||
{
|
||||
lpc43_tl_set_default_compare ();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool set = lpc43_tl_set_calc_arm (curr, toSet, true);
|
||||
if (!set)
|
||||
{
|
||||
/* signal call, force interrupt handler */
|
||||
|
||||
call = true;
|
||||
lpc43_tl_force_int ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* signal call, force interrupt handler */
|
||||
|
||||
call = true;
|
||||
lpc43_tl_force_int ();
|
||||
}
|
||||
|
||||
irqrestore (flags);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
int up_timer_cancel(FAR struct timespec *ts)
|
||||
{
|
||||
/*TODO*/
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
irqrestore (flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int up_timer_start(FAR const struct timespec *ts)
|
||||
{
|
||||
/*TODO*/
|
||||
irqstate_t flags;
|
||||
flags = irqsave ();
|
||||
|
||||
irqrestore (flags);
|
||||
return OK;
|
||||
}
|
||||
|
||||
# endif /* CONFIG_SCHED_TICKLESS_ALARM */
|
||||
|
||||
#endif /* CONFIG_SCHED_TICKLESS */
|
||||
Loading…
Add table
Add a link
Reference in a new issue