Резюме
Я пытаюсь написать встроенное приложение для MC9S12VR микроконтроллера . Это 16-битный микроконтроллер, но некоторые значения, с которыми я имею дело, имеют ширину 32 бита, и во время отладки я зафиксировал некоторые аномальные значения, которые, по-видимому, связаны с разорванным чтением.
Я пишу прошивку для этого микро-устройства в C89 и запускаю его через компилятор Freescale HC12 , и мне интересно, есть ли у кого-нибудь какие-либо предложения о том, как предотвратить их на этом конкретном микроконтроллере, предполагая, что это тот случай.
Подробнее
Часть моего приложения включает в себя управление двигателем и оценку его положения и скорости на основе импульсов, генерируемых датчиком (импульс генерируется при каждом полном обороте двигателя).
Чтобы это работало, мне нужно настроить один из таймеров MCU, чтобы я мог отслеживать время, прошедшее между импульсами. Однако таймер имеет тактовую частоту 3 МГц (после предварительного масштабирования), а регистр счетчика таймера является только 16-битным, поэтому счетчик переполняется каждые ~ 22 мс. Чтобы компенсировать это, я установил обработчик прерываний, который запускает переполнение счетчика таймера, и это увеличивает переменную «переполнение» на 1:
// TEMP
static volatile unsigned long _timerOverflowsNoReset;
// ...
#ifndef __INTELLISENSE__
__interrupt VectorNumber_Vtimovf
#endif
void timovf_isr(void)
{
// Clear the interrupt.
TFLG2_TOF = 1;
// TEMP
_timerOverflowsNoReset++;
// ...
}
Затем я могу определить текущее время из этого:
// TEMP
unsigned long MOTOR_GetCurrentTime(void)
{
const unsigned long ticksPerCycle = 0xFFFF;
const unsigned long ticksPerMicrosecond = 3; // 24 MHZ / 8 (prescaler)
const unsigned long ticks = _timerOverflowsNoReset * ticksPerCycle + TCNT;
const unsigned long microseconds = ticks / ticksPerMicrosecond;
return microseconds;
}
В main.c
я временно написал некоторый код отладки, который управляет двигателем в одном направлении, а затем регулярно делает «снимки» различных данных:
// Test
for (iter = 0; iter < 10; iter++)
{
nextWait += SECONDS(secondsPerIteration);
while ((_test2Snapshots[iter].elapsed = MOTOR_GetCurrentTime() - startTime) < nextWait);
_test2Snapshots[iter].position = MOTOR_GetCount();
_test2Snapshots[iter].phase = MOTOR_GetPhase();
_test2Snapshots[iter].time = MOTOR_GetCurrentTime() - startTime;
// ...
В этом тесте я читаю MOTOR_GetCurrentTime()
в двух местах очень близко друг к другу в коде и назначаю их свойствам глобально доступной структуры.
Практически в каждом случае я считаю, что первое считанное значение находится на несколько микросекунд после точки, в которой цикл while должен завершиться, а второе чтение - через несколько микросекунд - это ожидаемо. Тем не менее, иногда я нахожу, что первое чтение значительно выше, чем точка, в которой цикл должен завершиться, а затем второе чтение на меньше первого значения (а также значения завершения).
На скриншоте ниже приведен пример этого. Потребовалось около 20 повторений теста, прежде чем я смог воспроизвести его. В коде <snapshot>.elapsed
записывается до <snapshot>.time
, поэтому я ожидаю, что оно будет иметь немного меньшее значение:
Для snapshot[8]
мое приложение сначала читает 20010014
(более чем на 10 мсек после того, как оно должно было завершить цикл занятости), а , затем читает 19988209
. Как я упоминал выше, переполнение происходит каждые 22 мсек - в частности, разница в _timerOverflowsNoReset
одного устройства будет давать разницу в 65535 / 3
в вычисленном микросекундном значении. Если учесть это:
Разница в 40 не так уж и сильно отличается от того, что я вижу между моими другими парами чтений (~ 23/24), так что я предполагаю, что происходит какая-то слеза, связанная с чтением по одному _timerOverflowsNoReset
. Как и во время цикла занятости, он будет выполнять один вызов MOTOR_GetCurrentTime()
, который ошибочно воспринимает _timerOverflowsNoReset
как единицу больше, чем есть на самом деле, вызывая преждевременное завершение цикла, а затем при следующем чтении после этого он видит правильное значение еще раз.
У меня есть другие проблемы с моим приложением, из-за которых у меня возникают проблемы с фиксацией, и я надеюсь, что, если я решу это, это может решить и другие проблемы, если они имеют аналогичную причину.
Редактировать: Среди прочих изменений я изменил _timerOverflowsNoReset
и некоторые другие глобальные переменные с 32-битного без знака на 16-битный без знака в реализации, которую я сейчас имею.