Мне необходимо обрабатывать событие в прерывание таймера с частотой 2 - 4 МГц
Но столкнулся с такой проблемой:
Выставляю Processor clock = 235929600 Гц, Master clock = 117964800 Гц.
Настраиваю таймер на генерацию прерывания при достижении значения счетного регистра = RC.
Предделитель таймера = 2.
При таких параметрах для генерации прерывания с частотой приблизительно 2 МГц мне нужно записать число 30 в регистр RC.
Записываю, проверяю осцилографом (во время прерывания "дергаю" уровень вывода контроллера) - частота около 968 кГц. То есть меньше чем положено...
Записываю в регистр RC значение 64, осцилографом как и положено наблюдаю частоту 921600.
Записываю в регистр RC значения > 64, осцилографом наблюдаю то, что и должен.
Записываю в регистр RC значения < 64, осцилографом наблюдаю частоту не выше 968 кГц. При этом импулсь дергается по временной оси. (осцилограф адекватный для сигнала).
Что это? Проблема контроллера? Она известна? Или имеется ошибка?
Ниже привожу код инициализации PLL, таймера и обработчик прерывания таймера.
Фрагмент lowlevelinit
Код
// PLLA 235.9296 MHz
#define MUL_PLLA (128UL)
#define DIV_PLLA (10UL)
#define PLLA_FREQ ((MAIN_OSC_CLK*MUL_PLLA)/DIV_PLLA)
#define Pclk (PLLA_FREQ) // 235.9296 MHz
#define Fmclk (Pclk/2) // 117.9648 MHz
#define DELAY_PLL 100000
#define DELAY_MAIN_FREQ 100000
AT91C_BASE_PMC->PMC_MOR = (((AT91C_CKGR_OSCOUNT & (0x40 << 8)) | AT91C_CKGR_MOSCEN));
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
if (PLLA_FREQ >= 190000000)
{
AT91C_BASE_PMC->PMC_PLLAR = AT91C_CKGR_SRCA |
AT91C_CKGR_OUTA_2 |
(AT91C_CKGR_DIVA & ( DIV_PLLA << 0)) |
(AT91C_CKGR_MULA & ((MUL_PLLA-1) << 16)) |
(AT91C_CKGR_PLLACOUNT & (6 << 8));
}
else
{
AT91C_BASE_PMC->PMC_PLLAR = AT91C_CKGR_SRCA |
AT91C_CKGR_OUTA_0 |
(AT91C_CKGR_DIVA & ( DIV_PLLA << 0)) |
(AT91C_CKGR_MULA & ((MUL_PLLA-1) << 16)) |
(AT91C_CKGR_PLLACOUNT & (6 << 8));
}
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK | AT91C_PMC_MDIV_2;
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
#define MUL_PLLA (128UL)
#define DIV_PLLA (10UL)
#define PLLA_FREQ ((MAIN_OSC_CLK*MUL_PLLA)/DIV_PLLA)
#define Pclk (PLLA_FREQ) // 235.9296 MHz
#define Fmclk (Pclk/2) // 117.9648 MHz
#define DELAY_PLL 100000
#define DELAY_MAIN_FREQ 100000
AT91C_BASE_PMC->PMC_MOR = (((AT91C_CKGR_OSCOUNT & (0x40 << 8)) | AT91C_CKGR_MOSCEN));
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
if (PLLA_FREQ >= 190000000)
{
AT91C_BASE_PMC->PMC_PLLAR = AT91C_CKGR_SRCA |
AT91C_CKGR_OUTA_2 |
(AT91C_CKGR_DIVA & ( DIV_PLLA << 0)) |
(AT91C_CKGR_MULA & ((MUL_PLLA-1) << 16)) |
(AT91C_CKGR_PLLACOUNT & (6 << 8));
}
else
{
AT91C_BASE_PMC->PMC_PLLAR = AT91C_CKGR_SRCA |
AT91C_CKGR_OUTA_0 |
(AT91C_CKGR_DIVA & ( DIV_PLLA << 0)) |
(AT91C_CKGR_MULA & ((MUL_PLLA-1) << 16)) |
(AT91C_CKGR_PLLACOUNT & (6 << 8));
}
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
AT91C_BASE_PMC->PMC_MCKR = AT91C_PMC_PRES_CLK | AT91C_PMC_MDIV_2;
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
Инициализация таймера
Код
void init_tc0(unsigned int tc0_rc_value, unsigned int tc0_clks_timer_div, unsigned int tc0_interrupt_level)
{
volatile unsigned long dummy;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_IDR = 0xFFFFFFFF;
dummy = AT91C_BASE_TC0->TC_SR;
AT91C_BASE_TC0->TC_CMR = tc0_clks_timer_div | AT91C_TC_CPCTRG;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_TC0);
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned long) tc0_irq_handler;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | tc0_interrupt_level;
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC0);
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_RC = tc0_rc_value;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
}
{
volatile unsigned long dummy;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC0->TC_IDR = 0xFFFFFFFF;
dummy = AT91C_BASE_TC0->TC_SR;
AT91C_BASE_TC0->TC_CMR = tc0_clks_timer_div | AT91C_TC_CPCTRG;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_TC0);
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned long) tc0_irq_handler;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | tc0_interrupt_level;
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC0);
AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_TC0);
AT91C_BASE_TC0->TC_RC = tc0_rc_value;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
}
Обработчик прерывания таймера
Код
__inline void tc0_irq_handler(void)
{
volatile unsigned long dummy;
dummy = AT91C_BASE_TC0->TC_SR;
AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA7;
AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA7;
}
{
volatile unsigned long dummy;
dummy = AT91C_BASE_TC0->TC_SR;
AT91C_BASE_PIOA->PIO_SODR = AT91C_PIO_PA7;
AT91C_BASE_PIOA->PIO_CODR = AT91C_PIO_PA7;
}
Подскажите из-за чего такая проблема.