mirror of https://github.com/ARMmbed/mbed-os.git
Cleaned up some formatting issues.
parent
82a58ac94d
commit
401674284a
|
@ -76,110 +76,110 @@ static ADI_TMR_TypeDef * adi_tmr_registers[ADI_TMR_DEVICE_NUM] = {pADI_TMR0, pAD
|
||||||
*---------------------------------------------------------------------------*/
|
*---------------------------------------------------------------------------*/
|
||||||
static void GP1CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
|
static void GP1CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
|
||||||
{
|
{
|
||||||
Upper_count++;
|
Upper_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t get_current_time(void)
|
static uint32_t get_current_time(void)
|
||||||
{
|
{
|
||||||
uint16_t tmrcnt0, tmrcnt1;
|
uint16_t tmrcnt0, tmrcnt1;
|
||||||
uint32_t totaltmr0, totaltmr1;
|
uint32_t totaltmr0, totaltmr1;
|
||||||
uint32_t uc1, tmrpend0, tmrpend1;
|
uint32_t uc1, tmrpend0, tmrpend1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
volatile uint32_t *ucptr = &Upper_count;
|
volatile uint32_t *ucptr = &Upper_count;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Carefully coded to prevent race conditions. Do not make changes unless you understand all the
|
* Carefully coded to prevent race conditions. Do not make changes unless you understand all the
|
||||||
* implications.
|
* implications.
|
||||||
*
|
*
|
||||||
* Note this function can be called with interrupts globally disabled or enabled. It has been coded to work in both cases.
|
* Note this function can be called with interrupts globally disabled or enabled. It has been coded to work in both cases.
|
||||||
*
|
*
|
||||||
* TMR0 and TMR1 both run from the same synchronous clock. TMR0 runs at 26MHz and TMR1 runs at 26/256MHz.
|
* TMR0 and TMR1 both run from the same synchronous clock. TMR0 runs at 26MHz and TMR1 runs at 26/256MHz.
|
||||||
* TMR1 generates an interrupt every time it overflows its 16 bit counter. TMR0 runs faster and provides
|
* TMR1 generates an interrupt every time it overflows its 16 bit counter. TMR0 runs faster and provides
|
||||||
* the lowest 8 bits of the current time count. When TMR0 and TMR1 are combined, they provide 24 bits of
|
* the lowest 8 bits of the current time count. When TMR0 and TMR1 are combined, they provide 24 bits of
|
||||||
* timer precision. i.e. (TMR0.CURCNT & 0xff) + (TMR1.CURCNT << 8)
|
* timer precision. i.e. (TMR0.CURCNT & 0xff) + (TMR1.CURCNT << 8)
|
||||||
*
|
*
|
||||||
* There are several race conditions protected against:
|
* There are several race conditions protected against:
|
||||||
* 1. TMR0 and TMR1 are both read at the same time, however, on rare occasions, one will have incremented before the other.
|
* 1. TMR0 and TMR1 are both read at the same time, however, on rare occasions, one will have incremented before the other.
|
||||||
* Therefore we read both timer counters, and check if the middle 8 bits match, if they don't then read the counts again
|
* Therefore we read both timer counters, and check if the middle 8 bits match, if they don't then read the counts again
|
||||||
* until they do. This ensures that one or the other counters are stable with respect to each other.
|
* until they do. This ensures that one or the other counters are stable with respect to each other.
|
||||||
*
|
*
|
||||||
* 2. TMR1.CURCNT and Upper_count racing. Prevent this by disabling the TMR1 interrupt, which stops Upper_count increment interrupt (GP1CallbackFunction).
|
* 2. TMR1.CURCNT and Upper_count racing. Prevent this by disabling the TMR1 interrupt, which stops Upper_count increment interrupt (GP1CallbackFunction).
|
||||||
* Then check pending bit of TMR1 to see if we missed Upper_count interrupt, and add it manually later.
|
* Then check pending bit of TMR1 to see if we missed Upper_count interrupt, and add it manually later.
|
||||||
*
|
*
|
||||||
* 3. Race between the TMR1 pend, and the TMR1.CURCNT read. Even with TMR1 interrupt disabled, the pend bit
|
* 3. Race between the TMR1 pend, and the TMR1.CURCNT read. Even with TMR1 interrupt disabled, the pend bit
|
||||||
* may be set while TMR1.CURCNT is being read. We don't know if the pend bit matches the TMR1 state.
|
* may be set while TMR1.CURCNT is being read. We don't know if the pend bit matches the TMR1 state.
|
||||||
* To prevent this, the pending bit is read twice, and we see if it matches; if it doesn't, loop around again.
|
* To prevent this, the pending bit is read twice, and we see if it matches; if it doesn't, loop around again.
|
||||||
*
|
*
|
||||||
* Note the TMR1 interrupt is enabled on each iteration of the loop to flush out any pending TMR1 interrupt,
|
* Note the TMR1 interrupt is enabled on each iteration of the loop to flush out any pending TMR1 interrupt,
|
||||||
* thereby clearing any TMR1 pend's. This have no effect if this routine is called with interrupts globally disabled.
|
* thereby clearing any TMR1 pend's. This have no effect if this routine is called with interrupts globally disabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NVIC_DisableIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]); // Prevent Upper_count increment
|
NVIC_DisableIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]); // Prevent Upper_count increment
|
||||||
tmrpend0 = NVIC_GetPendingIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]);
|
tmrpend0 = NVIC_GetPendingIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]);
|
||||||
// Check if there is a pending interrupt for timer 1
|
// Check if there is a pending interrupt for timer 1
|
||||||
|
|
||||||
__DMB(); // memory barrier: read GP0 before GP1
|
__DMB(); // memory barrier: read GP0 before GP1
|
||||||
|
|
||||||
tmrcnt0 = adi_tmr_registers[ADI_TMR_DEVICE_GP0]->CURCNT; // to minimize skew, read both timers manually
|
tmrcnt0 = adi_tmr_registers[ADI_TMR_DEVICE_GP0]->CURCNT; // to minimize skew, read both timers manually
|
||||||
|
|
||||||
__DMB(); // memory barrier: read GP0 before GP1
|
__DMB(); // memory barrier: read GP0 before GP1
|
||||||
|
|
||||||
tmrcnt1 = adi_tmr_registers[ADI_TMR_DEVICE_GP1]->CURCNT; // read both timers manually
|
tmrcnt1 = adi_tmr_registers[ADI_TMR_DEVICE_GP1]->CURCNT; // read both timers manually
|
||||||
|
|
||||||
totaltmr0 = tmrcnt0; // expand to u32 bits
|
totaltmr0 = tmrcnt0; // expand to u32 bits
|
||||||
totaltmr1 = tmrcnt1; // expand to u32 bits
|
totaltmr1 = tmrcnt1; // expand to u32 bits
|
||||||
|
|
||||||
tmrcnt0 &= 0xff00u;
|
tmrcnt0 &= 0xff00u;
|
||||||
tmrcnt1 <<= 8;
|
tmrcnt1 <<= 8;
|
||||||
|
|
||||||
__DMB();
|
__DMB();
|
||||||
|
|
||||||
uc1 = *ucptr; // Read Upper_count
|
uc1 = *ucptr; // Read Upper_count
|
||||||
|
|
||||||
tmrpend1 = NVIC_GetPendingIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]);
|
tmrpend1 = NVIC_GetPendingIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]);
|
||||||
// Check for a pending interrupt again. Only leave loop if they match
|
// Check for a pending interrupt again. Only leave loop if they match
|
||||||
|
|
||||||
NVIC_EnableIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]); // enable interrupt on every loop to allow TMR1 interrupt to run
|
NVIC_EnableIRQ(adi_tmr_interrupt[ADI_TMR_DEVICE_GP1]); // enable interrupt on every loop to allow TMR1 interrupt to run
|
||||||
} while ((tmrcnt0 != tmrcnt1) || (tmrpend0 != tmrpend1));
|
} while ((tmrcnt0 != tmrcnt1) || (tmrpend0 != tmrpend1));
|
||||||
|
|
||||||
totaltmr1 <<= 8; // Timer1 runs 256x slower
|
totaltmr1 <<= 8; // Timer1 runs 256x slower
|
||||||
totaltmr1 += totaltmr0 & 0xffu; // Use last 8 bits of Timer0 as it runs faster
|
totaltmr1 += totaltmr0 & 0xffu; // Use last 8 bits of Timer0 as it runs faster
|
||||||
// totaltmr1 now contain 24 bits of significance
|
// totaltmr1 now contain 24 bits of significance
|
||||||
|
|
||||||
if (tmrpend0) { // If an interrupt is pending, then increment local copy of upper count
|
if (tmrpend0) { // If an interrupt is pending, then increment local copy of upper count
|
||||||
uc1++;
|
uc1++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Uc = totaltmr1; // expand out to 64 bits unsigned
|
uint64_t Uc = totaltmr1; // expand out to 64 bits unsigned
|
||||||
Uc += ((uint64_t) uc1) << 24; // Add on the upper count to get the full precision count
|
Uc += ((uint64_t) uc1) << 24; // Add on the upper count to get the full precision count
|
||||||
|
|
||||||
// Divide Uc by 26 (26MHz converted to 1MHz) todo scale for other clock freqs
|
// Divide Uc by 26 (26MHz converted to 1MHz) todo scale for other clock freqs
|
||||||
|
|
||||||
Uc *= 1290555u; // Divide total(1/26) << 25
|
Uc *= 1290555u; // Divide total(1/26) << 25
|
||||||
Uc >>= 25; // shift back. Fixed point avoid use of floating point divide.
|
Uc >>= 25; // shift back. Fixed point avoid use of floating point divide.
|
||||||
// Compiler does this inline using shifts and adds.
|
// Compiler does this inline using shifts and adds.
|
||||||
|
|
||||||
return Uc;
|
return Uc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void calc_event_counts(uint32_t timestamp)
|
static void calc_event_counts(uint32_t timestamp)
|
||||||
{
|
{
|
||||||
uint32_t calc_time, blocks, offset;
|
uint32_t calc_time, blocks, offset;
|
||||||
uint64_t aa;
|
uint64_t aa;
|
||||||
|
|
||||||
calc_time = get_current_time();
|
calc_time = get_current_time();
|
||||||
offset = timestamp - calc_time; // offset in useconds
|
offset = timestamp - calc_time; // offset in useconds
|
||||||
|
|
||||||
if (offset > 0xf0000000u) // if offset is a really big number, assume that timer has already expired (i.e. negative)
|
if (offset > 0xf0000000u) // if offset is a really big number, assume that timer has already expired (i.e. negative)
|
||||||
offset = 0u;
|
offset = 0u;
|
||||||
|
|
||||||
if (offset > 10u) { // it takes 10us to user timer routine after interrupt. Offset timer to account for that.
|
if (offset > 10u) { // it takes 10us to user timer routine after interrupt. Offset timer to account for that.
|
||||||
offset -= 10u;
|
offset -= 10u;
|
||||||
} else
|
} else
|
||||||
offset = 0u;
|
offset = 0u;
|
||||||
|
|
||||||
aa = (uint64_t) offset;
|
aa = (uint64_t) offset;
|
||||||
aa *= 26u; // convert from 1MHz to 26MHz clock. todo scale for other clock freqs
|
aa *= 26u; // convert from 1MHz to 26MHz clock. todo scale for other clock freqs
|
||||||
|
@ -187,25 +187,26 @@ static void calc_event_counts(uint32_t timestamp)
|
||||||
blocks = aa >> 7;
|
blocks = aa >> 7;
|
||||||
blocks++; // round
|
blocks++; // round
|
||||||
|
|
||||||
largecnt = blocks>>1; // communicate to event_timer() routine
|
largecnt = blocks>>1; // communicate to event_timer() routine
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_timer()
|
static void event_timer()
|
||||||
{
|
{
|
||||||
if (largecnt) {
|
if (largecnt) {
|
||||||
uint32_t cnt = largecnt;
|
uint32_t cnt = largecnt;
|
||||||
|
|
||||||
if (cnt > 65535u) {
|
if (cnt > 65535u) {
|
||||||
cnt = 0u;
|
cnt = 0u;
|
||||||
} else
|
} else {
|
||||||
cnt = 65536u - cnt;
|
cnt = 65536u - cnt;
|
||||||
|
}
|
||||||
|
|
||||||
tmr2Config.nLoad = cnt;
|
tmr2Config.nLoad = cnt;
|
||||||
tmr2Config.nAsyncLoad = cnt;
|
tmr2Config.nAsyncLoad = cnt;
|
||||||
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmr2Config);
|
adi_tmr_ConfigTimer(ADI_TMR_DEVICE_GP2, &tmr2Config);
|
||||||
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
|
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, true);
|
||||||
} else {
|
} else {
|
||||||
us_ticker_irq_handler();
|
us_ticker_irq_handler();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,16 +223,16 @@ static void event_timer()
|
||||||
*/
|
*/
|
||||||
static void GP2CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
|
static void GP2CallbackFunction(void *pCBParam, uint32_t Event, void * pArg)
|
||||||
{
|
{
|
||||||
if (largecnt >= 65536u) {
|
if (largecnt >= 65536u) {
|
||||||
largecnt -= 65536u;
|
largecnt -= 65536u;
|
||||||
} else {
|
} else {
|
||||||
largecnt = 0;
|
largecnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (largecnt < 65536u) {
|
if (largecnt < 65536u) {
|
||||||
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, false);
|
adi_tmr_Enable(ADI_TMR_DEVICE_GP2, false);
|
||||||
event_timer();
|
event_timer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -326,8 +327,8 @@ void us_ticker_set_interrupt(timestamp_t timestamp)
|
||||||
* This MUST not be called if another timer event is currently enabled.
|
* This MUST not be called if another timer event is currently enabled.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
calc_event_counts(timestamp); // use timestamp to calculate largecnt to control number of timer interrupts
|
calc_event_counts(timestamp); // use timestamp to calculate largecnt to control number of timer interrupts
|
||||||
event_timer(); // uses largecnt to initiate timer interrupts
|
event_timer(); // uses largecnt to initiate timer interrupts
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set pending interrupt that should be fired right away.
|
/** Set pending interrupt that should be fired right away.
|
||||||
|
|
Loading…
Reference in New Issue