Основных функциий у ПДУ две — выводить информацию о состоянии дизельных установок и электросистемы в целом, обеспечивать необходимый минимум функций управления и контроля. А… еще, в случае чего, сообщать, что враги ворвались в отсек 🙂
Все это обеспечивается набором диодов, сегментных индикаторов и тремя кнопками. Ну и, конечно же, прошивкой микроконтроллера платы.
Недавно от Заказчика поступила просьба о некоторой доработке функционала ПДУ, заодно решили разобраться с багой, до которой раньше руки никак не доходили.
И вот, время от времени неправильно срабатывают диоды — либо загораются выключенные, либо включенные срабатывают не тем цветом. Процесс носит характер кратковременного промаргивания, но глазу это заметно. Особенно в полутьме завода. При предварительном тестировании в лаборатории перед отгрузкой подобного эффекта не наблюдалось.
Естественно, такие проколы оставлять нельзя — а то вместо деликатного намека, что так быть не должно, можно в неудачный момент получить официальную бумагу-претензию. Ваша, мол, штука плохо работает… Хотя реально на функциональность этот глюк не влиял.
Запустили боевую программу, которая реально ставится на ПМУ, зациклили простенький тест — заполнить все диоды то одним цветом, то другим. И действительно — бежит фронт зеленого цвета, вдруг перед ним зажигается красная полоса и тут же гаснет.
Стали разбираться.Изначально мысль была одна — где-то портится буфер. Осталось только найти где и как — просто в программе или из-за неправильного распределения памяти.
Однако, поиски результата не дали. Оно и не удивительно — реально причина оказалась оказалась в другом.
Диоды, из-за их большого количества (48 шт), подключены через сдвиговые регистры, а вывод осуществляется по spi. Обновление — по таймеру на спи отправляется массив, хранящий состояние всех диодов. Т.е. время от времени срабатывает функция вида:
void sendbyte( unsigned char x ) {
unsigned char i;
for ( i = 0; i < 8; i++ ) {
// здесь забиваем в спи порт все 8 бит отправляемого байта
}
}
При этом остаются включенными прерывания, и, так как в усарт постоянно приходит информация, прец все-время уходит на обработку rx-прерывания — из-за чего между отправкой битов по спи может наступить большой тупняк и пауза. Так делать нельзя — чтобы все работало четко, как часы, отправка должна быть быстрой и непрерывной.
Лечение баги заняло ровно две строчки:
void sendbyte( unsigned char x ) {
unsigned char i;
__disable_interrupt();
for ( i = 0; i < 8; i++ ) {
// здесь забиваем в спи порт все 8 бит отправляемого байта
}
__enable_interrupt();
}