После некоторой паузы опять вернулся к выправлению кода измерения частоты. Что я понял: да, действительно я так мерил именно пол периода. Делалось это по той причине, что если я настраиваю оба действия (триггер и запись в RA) по одному и тому же фронту, то реально таймер отсчитывает и пишет в RA то правильное кол-во импульсов, то за пол периода, притом чаще именно за пол периода. Почему - не понял до сих пор. И, кроме того, похоже, что иногда вообще считывается 0, т.е., как будто TC успевает сброситься раньше, чем записаться RA...
Чтобы уйти от этих неопределённостей я настроил триггер TIOA и запись в RA по ОБОИМ фронтам, и отсчитанные полупериоды просто складываю. Осталась неопределённость с нулём. Я пока не придумал ничего лучшего, как просто игнорировать нулевые значения. Вот, собственно, так теперь оно работает.
Инициализация:
Код
TachoSensor::TachoSensor (char *Name, char TimerNumber) : BaseSensor(Name, 0, Parameters.SpeedLimitHard * 3)
{
m_SomeCoeff = ( (BSP_CPU_ClkFreq() * 1000) >> 7);
m_TimerID = AT91C_ID_TC0;
m_TC = AT91C_BASE_TC0;
m_PrevVal = 0;
m_CurrVal = 0;
//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_BOTH | // Triggers on both edge
AT91C_TC_ABETRG | // Use TIOA0 as external trigger
AT91C_TC_LDRA_BOTH; // Load RA on both edge of TIOA0
//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.
// AT91C_TC_ETRGS; //Enable ext. trigger int.
AT91C_BASE_TCB->TCB_TC0.TC_CCR = AT91C_TC_CLKEN; /* TC0 timer enabled */
} /* TachoSensor::TachoSensor */
Обработчик:
Код
void TachoSensor::ISR_Handler ()
{
AT91C_BASE_AIC->AIC_IVR = 0; /* Write the IVR, as required in Protection Mode */
unsigned int Status = m_TC->TC_SR;
if (Status & AT91C_TC_COVFS)
{
OvfCnt = true;
*m_ValPtr = 0; // Считаем, что 0 (несущественная)
}
if (Status & AT91C_TC_LDRAS)
{
if (m_SemiPeriod)
{
m_SemiVal1 = AT91C_BASE_TC0->TC_RA;
m_SemiPeriod = false;
}
else
{
m_SemiVal2 = AT91C_BASE_TC0->TC_RA;
m_SemiPeriod = true;
}
m_PrevVal = m_CurrVal;
if (m_SemiVal1 && m_SemiVal2) // Почему-то иногда из TC_RA считывается 0, такие значения игнорируем.
m_CurrVal = m_SemiVal1 + m_SemiVal2;
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 */