Задумка: с помощью ТС0 в режиме capture измерять частоту со входа TIOA0 (частота порядка 1000 - 4000 Гц). Сам TC0 должен тактироваться MCK/128.
Реально же получается, будто TC0 тактируется частотой, близкой к MCK/228 (судя по частоте с генератора и получаемым в *m_ValPtr значениям). Причём наблюдаю ещё один непонятный эффект: нелинейность измеренного значения частоты, процентов 10-15.
Так инициализирую:
Код
// BSP_CPU_ClkFreq() даёт частоту MCK в кГц
m_SomeCoeff = ( (BSP_CPU_ClkFreq() *1000) / 128); // Более-менее реальные показания удаётся получить, если 128 заменить на 228
m_TimerID = AT91C_ID_TC0;
m_TC = AT91C_BASE_TC0;
//Timer configuration
AT91C_BASE_PMC->PMC_PCER = (1 << m_TimerID); /* Enable the peripheral clk */
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_CLKDIS; /* TC0 timer disabled */
m_TC->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK | // ~48MHz/128
AT91C_TC_ETRGEDG_FALLING | // Triggers on falling edge
AT91C_TC_ABETRG | // Use TIOA0 as external trigger
AT91C_TC_LDRA_RISING; // Load RA on RISING edge of TIOA0
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; /* TC0 timer enabled */
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_SWTRG; /* SWTRG to reset and start */
//AIC configuration
AT91C_BASE_AIC->AIC_SVR[m_TimerID] = (INT32U)TachoSensor::ISR_Handler;
AT91C_BASE_AIC->AIC_SMR[m_TimerID] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
| AT91C_AIC_PRIOR_LOWEST;
AT91C_BASE_AIC->AIC_ICCR = 1 << m_TimerID;
AT91C_BASE_AIC->AIC_IECR = 1 << m_TimerID;
m_TC->TC_IER = AT91C_TC_COVFS | //Enable Counter Overflow interrupt
AT91C_TC_LDRAS;// | //Enable RA loading int.
m_TC->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
m_SomeCoeff = ( (BSP_CPU_ClkFreq() *1000) / 128); // Более-менее реальные показания удаётся получить, если 128 заменить на 228
m_TimerID = AT91C_ID_TC0;
m_TC = AT91C_BASE_TC0;
//Timer configuration
AT91C_BASE_PMC->PMC_PCER = (1 << m_TimerID); /* Enable the peripheral clk */
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_CLKDIS; /* TC0 timer disabled */
m_TC->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK | // ~48MHz/128
AT91C_TC_ETRGEDG_FALLING | // Triggers on falling edge
AT91C_TC_ABETRG | // Use TIOA0 as external trigger
AT91C_TC_LDRA_RISING; // Load RA on RISING edge of TIOA0
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; /* TC0 timer enabled */
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_SWTRG; /* SWTRG to reset and start */
//AIC configuration
AT91C_BASE_AIC->AIC_SVR[m_TimerID] = (INT32U)TachoSensor::ISR_Handler;
AT91C_BASE_AIC->AIC_SMR[m_TimerID] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
| AT91C_AIC_PRIOR_LOWEST;
AT91C_BASE_AIC->AIC_ICCR = 1 << m_TimerID;
AT91C_BASE_AIC->AIC_IECR = 1 << m_TimerID;
m_TC->TC_IER = AT91C_TC_COVFS | //Enable Counter Overflow interrupt
AT91C_TC_LDRAS;// | //Enable RA loading int.
m_TC->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
А так обрабатываю прерывания:
Код
void TachoSensor::ISR_Handler ()
{
AT91C_BASE_AIC->AIC_IVR = 0;
unsigned int Status = m_TC->TC_SR;
if (Status & AT91C_TC_COVFS)
{
OvfCnt = true;
*m_ValPtr = 0; // Считаем, что 0 (несущественная)
}
if (Status & AT91C_TC_LDRAS)
{
m_PrevVal = m_CurrVal;
m_CurrVal = AT91C_BASE_TC0->TC_RA;
if (OvfCnt)
{
OvfCnt = false;
*m_ValPtr = 0; // Считаем, что 0 (несущественная)
}
else
{
if ( m_CurrVal != 0 )
{
*m_ValPtr = m_SomeCoeff / m_CurrVal;
}
}
}
AT91C_BASE_AIC->AIC_ICCR = 1 << m_TimerID;
AT91C_BASE_AIC->AIC_EOICR = 0; /* Signal end of interrupt */
} /* TachoSensor::ISR_Handler */
{
AT91C_BASE_AIC->AIC_IVR = 0;
unsigned int Status = m_TC->TC_SR;
if (Status & AT91C_TC_COVFS)
{
OvfCnt = true;
*m_ValPtr = 0; // Считаем, что 0 (несущественная)
}
if (Status & AT91C_TC_LDRAS)
{
m_PrevVal = m_CurrVal;
m_CurrVal = AT91C_BASE_TC0->TC_RA;
if (OvfCnt)
{
OvfCnt = false;
*m_ValPtr = 0; // Считаем, что 0 (несущественная)
}
else
{
if ( m_CurrVal != 0 )
{
*m_ValPtr = m_SomeCoeff / m_CurrVal;
}
}
}
AT91C_BASE_AIC->AIC_ICCR = 1 << m_TimerID;
AT91C_BASE_AIC->AIC_EOICR = 0; /* Signal end of interrupt */
} /* TachoSensor::ISR_Handler */