ZNeo: Calculation of timer reload and prescaler was wrong
This commit is contained in:
parent
ee86b7afb9
commit
7ee0706bc1
@ -7248,4 +7248,7 @@
|
|||||||
Windestam (2014-4-25)
|
Windestam (2014-4-25)
|
||||||
* configs/nucleo-f401re: Removed bogus references to the MPU
|
* configs/nucleo-f401re: Removed bogus references to the MPU
|
||||||
(2014-4-25).
|
(2014-4-25).
|
||||||
|
* arch/z16/src/z16f_timerisr.c: Fix calculation of timer
|
||||||
|
reload and prescaler. The timer frequency was way too fast
|
||||||
|
(2014-4-25).
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -43,19 +43,31 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
#include "chip/chip.h"
|
#include "chip/chip.h"
|
||||||
#include "clock_internal.h"
|
#include "clock_internal.h"
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Definitions
|
* Pre-processor Definitions
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
/* The desired timer interrupt frequency is provided by the definition
|
||||||
|
* CLOCKS_PER_SEC (see include/time.h). CLOCKS_PER_SEC defines the desired
|
||||||
|
* number of system clock ticks per second. That value is a user
|
||||||
|
* configurable setting that defaults to 100 (100 ticks per second = 10 MS
|
||||||
|
* interval).
|
||||||
|
*
|
||||||
|
* The RCC feeds the Cortex System Timer (SysTick) with the AHB clock (HCLK)
|
||||||
|
* divided by 8. The SysTick can work either with this clock or with the
|
||||||
|
* Cortex clock (HCLK), configurable in the SysTick Control and Status
|
||||||
|
* register.
|
||||||
|
*/
|
||||||
|
|
||||||
/* System clock frequency value from ZDS target settings */
|
/* System clock frequency value from ZDS target settings */
|
||||||
|
|
||||||
extern _Erom unsigned long SYS_CLK_FREQ;
|
extern _Erom uint8_t SYS_CLK_FREQ;
|
||||||
#define _DEFCLK ((unsigned long)&SYS_CLK_FREQ)
|
#define _DEFCLK ((uint32_t)&SYS_CLK_FREQ)
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
@ -97,39 +109,125 @@ int up_timerisr(int irq, uint32_t *regs)
|
|||||||
|
|
||||||
void up_timerinit(void)
|
void up_timerinit(void)
|
||||||
{
|
{
|
||||||
|
uint32_t reload;
|
||||||
|
uint32_t scaledfreq;
|
||||||
|
uint32_t rawdiv;
|
||||||
|
uint8_t divider;
|
||||||
|
uint8_t regval;
|
||||||
|
int shift;
|
||||||
|
|
||||||
up_disable_irq(Z16F_IRQ_SYSTIMER);
|
up_disable_irq(Z16F_IRQ_SYSTIMER);
|
||||||
|
|
||||||
/* Disable the timer and configure for divide by 1 and continuous mode. */
|
/* Disable the timer and configure for divide by 1 and continuous mode. */
|
||||||
|
|
||||||
putreg8( Z16F_TIMERSCTL1_DIV1 | Z16F_TIMERSCTL1_CONT, Z16F_TIMER0_CTL1);
|
regval = Z16F_TIMERSCTL1_DIV1 | Z16F_TIMERSCTL1_CONT;
|
||||||
|
putreg8(regval, Z16F_TIMER0_CTL1);
|
||||||
|
|
||||||
/* Assign an intial timer value */
|
/* Assign an initial timer value */
|
||||||
|
|
||||||
putreg16(0x0001, Z16F_TIMER0_HL);
|
putreg16(0x0001, Z16F_TIMER0_HL);
|
||||||
|
|
||||||
/* Set the timer reload value.
|
/* Calculate timer reload value (continuous mode)
|
||||||
*
|
|
||||||
* In continuous mode:
|
|
||||||
*
|
*
|
||||||
|
* timer_period = reload_value * divisor / system_clock_freqency
|
||||||
* timer_frequency = system_clock_freqency / divisor / reload_value
|
* timer_frequency = system_clock_freqency / divisor / reload_value
|
||||||
* or
|
* or
|
||||||
* reload_value = (system_clock_frequency / timer_frequency / divisor
|
* reload_value = (system_clock_frequency / timer_frequency / divisor
|
||||||
*
|
*
|
||||||
* For system_clock_frequency=200MHz, timer_frequency=100KHz, and divisor=1,
|
* The prescale value ranges from 1 to 128, the reload value must be less
|
||||||
* this yields 200.
|
* then or equal to 0xffff. We would like to select the smallest prescaler
|
||||||
|
* value and the largest reload value for the greatest accuracy.
|
||||||
|
*
|
||||||
|
* Example: system_clock_frequency=20MHz, timer_frequency=100Hz:
|
||||||
|
* scaledfreq = 20,000,000 / 100
|
||||||
|
* = 200,000
|
||||||
|
* rawdiv = (200,000 >> 16) + 1
|
||||||
|
* = 4
|
||||||
|
* divider = Z16F_TIMERSCTL1_DIV4
|
||||||
|
* shift = 2
|
||||||
|
* reload = 200,000 >> 2
|
||||||
|
* = 50,000
|
||||||
|
*
|
||||||
|
* Example: system_clock_frequency=18.432MHz, timer_frequency=100Hz:
|
||||||
|
* scaledfreq = 20,000,000 / 100
|
||||||
|
* = 200,000
|
||||||
|
* divisor = ((18,432,000 / 100) >> 16) + 1
|
||||||
|
* = 3 -> 4 (need to to up to next power of two)
|
||||||
|
* reload_value = 20,000,000 / 100 / 4
|
||||||
|
* = 56,080
|
||||||
*/
|
*/
|
||||||
|
|
||||||
putreg16(((uint32_t)_DEFCLK / 100000), Z16F_TIMER0_R);
|
#if 0 /* Does not work ??? */
|
||||||
|
scaledfreq = _DEFCLK / CLOCKS_PER_SEC;
|
||||||
|
#else
|
||||||
|
scaledfreq = (BOARD_SYSTEM_FREQUENCY / CLOCKS_PER_SEC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rawdiv = (scaledfreq >> 16) + 1;
|
||||||
|
if (rawdiv < 2)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV1;
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 3)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV2;
|
||||||
|
shift = 1;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 7)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV4;
|
||||||
|
shift = 2;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 15)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV8;
|
||||||
|
shift = 3;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 31)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV16;
|
||||||
|
shift = 4;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 63)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV32;
|
||||||
|
shift = 5;
|
||||||
|
}
|
||||||
|
else if (rawdiv < 127)
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV64;
|
||||||
|
shift = 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
divider = Z16F_TIMERSCTL1_DIV128;
|
||||||
|
shift = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
reload = scaledfreq >> shift;
|
||||||
|
DEBUGASSERT(reload <= 0xffff);
|
||||||
|
|
||||||
|
/* Set the timer reload value */
|
||||||
|
|
||||||
|
putreg16((uint16_t)reload, Z16F_TIMER0_R);
|
||||||
|
|
||||||
|
/* Set the prescale value */
|
||||||
|
|
||||||
|
regval = getreg8(Z16F_TIMER0_CTL1);
|
||||||
|
regval &= ~Z16F_TIMERSCTL1_DIVMASK;
|
||||||
|
regval |= divider;
|
||||||
|
putreg8(regval, Z16F_TIMER0_CTL1);
|
||||||
|
|
||||||
/* Enable the timer */
|
/* Enable the timer */
|
||||||
|
|
||||||
putreg8((getreg8(Z16F_TIMER0_CTL1) | Z16F_TIMERCTL1_TEN), Z16F_TIMER0_CTL1);
|
regval |= Z16F_TIMERCTL1_TEN;
|
||||||
|
putreg8(regval, Z16F_TIMER0_CTL1);
|
||||||
|
|
||||||
/* Set the timer priority */
|
/* Set the timer priority */
|
||||||
|
|
||||||
/* Attach and enable the timer interrupt (leaving at priority 0 */
|
/* Attach and enable the timer interrupt (leaving at priority 0) */
|
||||||
|
|
||||||
irq_attach(Z16F_IRQ_SYSTIMER, (xcpt_t)up_timerisr);
|
irq_attach(Z16F_IRQ_SYSTIMER, (xcpt_t)up_timerisr);
|
||||||
up_enable_irq(Z16F_IRQ_SYSTIMER);
|
up_enable_irq(Z16F_IRQ_SYSTIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user