Как определить почему МК перезагружается, если перезагрузка происходит при выводе в монитор?

123ksn
Offline
Зарегистрирован: 24.11.2014
Погуглил проблему. Вот неполный список причин почему МК может перезагружаться:
 
1)Плохое питание (Слабый источник, большой уровень пульсаций, контролируемый из вне источник питания(USB-port PC))
контроллер должен быть обязательно сброшен при напряжении питания ниже критического.
При снижении питания работающего МК может произойти все что угодно, вплоть до повреждения программы во флэши.
Не доверяю ни каким BODам, а ставлю внешний супервизор.
 
2)Помехи (Длинные провода питания, длинные провода к датчикам, вкл/выкл реле и др мощной нагрузки)
 
3)Перегрузка по току  как отдельного вывода, так и МК в целом (Ток на вывод может быть и 40мА, но в целом на МК, например, 120мА)
 
4)Неправильно выставленные фьюзы (включена "собака" watchdog, но в программе не сбрасывается, включен бит совместимости, бит контроля просадки напряжения BOD)
 
5)деление на ноль
 
6)Переполнение переменной, массива (например, выбран тип byte, а надо int ) 
??? unsigned long ii = 0; 32-битная переменная и, когда она заполнена, вызывает переполнение и перезагрузку
 
7)Плохой кварцевый резонатор (сам кварц, схема, конденсаторы обвязки, кварц не заземлен, не запрограммированный бит CKOPT - очень сильно влияет на амплитуду тактовых импульсов от кварца) поставьте ckopt галочку и посмотрите осциллографом с делителем 1/10 размах напряжения на ноге xtal2.
если там меньше 2/3 от напряжения питания- меняйте кварц илии его обвеску.
Использование внешних и встроенных керамических резонаторов крайне нежелательно ввиду зависимости частоты от температуры, от напряжения питания и других внешних факторов
 
8)Загрязнения на плате (флюс, пыль, насекомые, окислы)
 
9)Если не работает основной тактовый генератор, то WDT никак не осилит перезапуск.
 
10)неудачная разводка платы.
Иногда может повлиять толщина и материал дорожек.
Замечал что платы изготовленные разными подрядчиками по одному и тому же рисунку могут вести себя по разному.
некоторые (целые партии PCB) глючили - приходилось резать дорожку питания в непосредственной близости от МК и вставлять LC фильтр.
 
11)Компиляция с другими утилитами, параметрами, библиотеками, настройками (версии, билды и т.п.)
 
12)компьютерный блок питания. В незаземленном варианте на корпусе присутствует 110 Вольт, которые так и ищут куда бы стечь. Кроме того требуется какая-то минимальная нагрузка по линии 5 вольт (обычно 0,2-0,5 амп), а без неё напряжение на выходе прыгает с частотой от нескольких Hz до десятков Hz
 
13)USB-serial контроллер Arduino перезагружает МК каждый раз, когда терминальная программа (в т.ч. Serial monitor, встроенный в ПО Arduino IDE) устанавливает соединение. Реализовано это следующим образом: у USB-serial контроллера вывод DTR (Data Terminal Ready) связан с выводом RESET. Если программа, работающая с виртуальным последовательным портом, использует DTR, то при установке соединения МК перезагружается.
 
14)Подключена библиотека, но не подключено оборудование, соответствующее этой библиотеке.
 
15)Неинициализированные в программе переменные
 
16)Софт со стороны ПК (Sony Ericsson, вирусы), пытающийся периодически обращающийся к USB порту с целью определить, чем является подключеное USB-устройство (мобильным телефоном) (сигнал DTR дёргает ресет)
 
17)Использование рекурсии
 
 
************************
 
До сих пор мне хватало светодиода и Serial.print для отладки кода на МК (для предметности Atmega328).
Но вот наступил черный день, когда светодиод и Serial.print не выручают. Был мой рабочий проект на Ардуино Уно, я немного его доработал и проект перестал работать - МК уходит в перезагрузку. Внешне ничего не менялось (ПК, ОС, USB-кабель, IDE 1.6.0, библиотеки), т. е. перезагрузка происходит ИСКЛЮЧИТЕЛЬНО из-за моих изменений в скетче. При питании от внешнего БП 12В х 2А и отключенном кабеле USB, тоже перезагружается.
 
С одной стороны, я понимаю, что могу откатиться на старую рабочую версию и начать добавлять код "по строке" компилируя и контролируя работоспособность устройства. С другой стороны, делать мне этого не хочется, так как хочется узнать, как искать причину проблемы, когда перезагрузка происходит "на полуслове" при выводе информации в монитор последовательного порта Ардуино.
"Блиц криг" путем ремирования редактированного кода не сработал. Я отключил весь редактированный код, который вызывается из основного цикла (LOOP).  Из этого якобы следует, что проблемный код находится либо в переменных, либо в SETUP, либо в коде, который я не редактировал. Короче, в зависимости от того, что я ремирую, основной цикл прокручивается разное, но всегда одинаковое, количество раз. Т.е. с неким кодом крутится 100 раз и при выводе сообщения (первых двух символов) в монитор МК, перезагружается. Ремирую вызов некой подпрограммы - крутится 90 раз и при выводе сообщения (первого символа) перезагружается.
 
Собственно вопрос: Как определить почему МК перезагружается, если перезагрузка происходит при N-ом выводе в монитор Serial.print ?
Я думаю, но НЕ утверждаю, что на перезагрузку влияет эта подпрограмма.
LOOP()
.....
	Test_Time();
	Serial.println(F("Test_Time()"));
	
Serial.print(F("699_kol_ciklov="));
Serial.println(aaa);
aaa=aaa+1;
 }//********** Конец бесконечного цикла loop**************
void Test_Time()
{
	//if(millis()-Time_Termo > millis_prev_T)//прощло больше 1сек. так НЕЛЬЗЯ
        millisNow=millis();
        millis4Termo=millis_prev_T + Time_Termo;
        millis4UART=millis_prev_UART + PeriodToUART;

	Serial.print(F("_millisNow="));
        Serial.println(millisNow);

	Serial.print(F("_millis4Termo="));
        Serial.println(millis4Termo);

	Serial.print(F("_millis4UART="));
        Serial.println(millis4UART);


	if (millisNow >millis4Termo) //прощло больше 1000мсек(время измерения датчиком DS18b20 с запасом).
	{
	Serial.print(F("old_millis_prev_T="));
        Serial.println(millis_prev_T);
		
        millis_prev_T = millisNow;
	Flag_Time_Termo = 1;
	Serial.print(F("NEW_millis_prev_T="));
        Serial.println(millis_prev_T);

	}
	//static unsigned long millis_prev_UART;
	if (millisNow > millis4UART) //прощло больше PeriodToUART
	{
	Serial.print(F("old_millis_prev_UART="));
        Serial.println(millis_prev_UART);

	millis_prev_UART = millisNow;
	Flag_PeriodToUART = 1;
	Serial.print(F("NEW_millis_prev_UART="));
        Serial.println(millis_prev_UART);
	}

}//Конец Test_Time ()
NEW_milSet:9600,8,n,1)
 
Выводится часть строки (NEW_millis_prev_UART) из LOOP и строка (Set:9600,8,n,1)) из SETUP после перезагрузки
 
Особо интересует ответ на вопрос как такую причину перезагрузки (зависания) определить в протеусе 7.7sp4? (Вывод в терминал прекращен, но анимация продолжается)
И картинки
 
123ksn
Offline
Зарегистрирован: 24.11.2014

Да, забыл указать, что 

//переменные для счетчика времени работы программы
unsigned long millisNow = 0;
unsigned long millis4Termo = 0;
unsigned long millis4UART = 0;

//**********************Переменные для времени*************************************************
word PeriodToUART = 5000; //здесь 5сек. Период вывода информации(0-65535)милисек, т.е.до 65сек
word Time_Termo = 1000; //Время измерения температуры датчиком DS18b20 (0-65535)милисек, которое зависит от разрядности (9-12 бит)

unsigned long millis_prev_1 = 100000; //предыдущее время. для задержки. только ДО первого прерывания int1. Потом сравнивается текущее время с предыдущим (millis_prev_1)
unsigned long millis_prev_2 = 100000; //int0
unsigned long millis_prev_T = 1000000; //предыдущее время. для контроля паузы на преобразование температуры в датчиках
unsigned long millis_prev_UART = 1000000; //предыдущее время. для задержки вывода информации в UART, LCD, SD, AT24Cxx

void setup()
.......

millis_prev_T = millis();
millis_prev_UART=millis_prev_T;
}
//Конец setup()- функции настроек 


 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Не обнаружил еще одной довольно частой причины перезагрузки - нехватки оперативной памяти.

Во-первых, посмотрите, что пишет компиллятор обь оставшейся памяти.

А во-вторых, придирчиво изучите в коде места, где Вы пользуетесь нестатическими массивами (включая строки).

Ну и на форуме публиковалась функция для определения количества занятой и свободной памяти.

123ksn
Offline
Зарегистрирован: 24.11.2014

andriano пишет:

Не обнаружил еще одной довольно частой причины перезагрузки - нехватки оперативной памяти.

Во-первых, посмотрите, что пишет компиллятор обь оставшейся памяти.

А во-вторых, придирчиво изучите в коде места, где Вы пользуетесь нестатическими массивами (включая строки).

Ну и на форуме публиковалась функция для определения количества занятой и свободной памяти.

Действительно забыл указать, так как недостаток памяти - это очевидная причина. Жать только, что не всегда очевидно, что наступила её нехватка.

У меня памяти море. Функцию запускал. Показания почти такие же как у компилятора. Расхождение в несколько байт. Вот что пишет компилятор:

Sketch uses 13 962 bytes (43%) of program storage space. Maximum is 32 256 bytes.
Global variables use 713 bytes (34%) of dynamic memory, leaving 1 335 bytes for local variables. Maximum is 2 048 bytes.
Нестатические, т.е. динамические массивы не использую именно из-за боязни налететь на "подводный камень". Строки..... Хм...Проверю внимательнее, хотя я их не редактировал.
Т.е. Вы считаете, что такое проявление сбоя в работе из-за нехватки памяти?
 
Logik
Онлайн
Зарегистрирован: 05.08.2014

Повысь скорость сириала.

123ksn
Offline
Зарегистрирован: 24.11.2014

Logik пишет:

Повысь скорость сириала.

Я, конечно, этот вариант проверю, руки не отсохнут, но вообще-то я предпочитаю аргументированные рекомендации.

По поводу свободной памяти...

Вставил в основной цикл код проверки памяти:
Вроде качал здесь:
This is the excellent MemoryFree library from http://www.arduino.cc/playground/Code/AvailableMemory.
версия не указана.
 
//Подключил библиотеку
#include <MemoryFree.h>

//и в основной цикл вставил код проверки памяти
		Send_LCD();
	}
    Serial.print(F("freeMemory()="));
    Serial.println(freeMemory());

	Test_Time();
	Serial.println(F("Test_Time()"));
	
Serial.print(F("699_kol_ciklov="));
Serial.println(aaa);
aaa=aaa+1;
 }//*** Конец бесконечного цикла loop***
Удостоверился, что свободной памяти достаточно и её значение не изменяется.
 
freeMemory()=1317
 
Скачал еще одну версию программы определения свободной памяти, удалив предыдущую библиотеку. Кстати, при импорте библиотеки разместились не в папке c Arduino IDE, а в папке с проектами. Наверно это правильно, что разработчики отделяют родное от пришлого. Жаль только, что это никак не обозначается, например, цветом.
Поместил в свой LOOP. Компиляция прошла без проблем.
Free RAM = 1281
 

 

123ksn
Offline
Зарегистрирован: 24.11.2014

Проверил работу программы на скорости 115200. Результат на кртинке. Количество циклов возросло (ожидаемо!), а вот время работы программы до перезагрузки почти не изменилось. Как это понимать?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Короче, без полного кода - не обойтись. Выкладывайте весь.

Logik
Онлайн
Зарегистрирован: 05.08.2014

Понимать это просто - Вы выводите в порт быстрей, чем происзодит отправка, данные при вызове Serial.print помещаются в буфер если в нем есть место. Если нет - то в Serial.print будет ожидание освобождения места. А время этого ожидания напрямую зависит от скорости. Потому выводы из эксперимента. 1. Код очень интенсивно выводит в Serial, это плохо, т.к. тормозит выполнение. Неизвестно че там в тех либах и насколько они критичны к этому. 2. Обнаружена явная привязка ребута не к числу циклов, как описано в стартовом сообщении, а ко времени похоже 10000мс. Что там в коде делается в этот момент?

ПС. Отлаживать чужой код не видя его - как лечить по фотографии родственника ;)

123ksn
Offline
Зарегистрирован: 24.11.2014

DIYMan пишет:

Короче, без полного кода - не обойтись. Выкладывайте весь.

Кода мне не жалко, но он не "причесан" и ОЧЕНЬ сильно комментирован. Выложить как есть - это спровоцировать, пардон, срачь в теме. А причесывать нынешний полуфабрикат долго.

Кроме того, меня больше интересует академическая сторона вопроса. Т.е. есть проблема и как её решить не методом перебора или "научного тыка", а методом "квалифицированного инженера".  Это знаете, как ремонтрировать телевизор проверяя все детали.  А можно на основании пары измерений сказать, что, к примеру, не работает кадровая развертка и проверять только этот блок. С этой точки зрения, IMHO, я дал информации достаточно.

 

123ksn
Offline
Зарегистрирован: 24.11.2014

Logik пишет:

Понимать это просто - Вы выводите в порт быстрей, чем происзодит отправка, данные при вызове Serial.print помещаются в буфер если в нем есть место. Если нет - то в Serial.print будет ожидание освобождения места. А время этого ожидания напрямую зависит от скорости. Потому выводы из эксперимента. 1. Код очень интенсивно выводит в Serial, это плохо, т.к. тормозит выполнение. Неизвестно че там в тех либах и насколько они критичны к этому. 2. Обнаружена явная привязка ребута не к числу циклов, как описано в стартовом сообщении, а ко времени похоже 10000мс. Что там в коде делается в этот момент?

Вообще-то Вы повторили то, что сказал я, только другими словами. Я тоже думал о 10.000. Но это ни к чему не привязать (типу данных, переполнению и т.п.)

Logik пишет:

ПС. Отлаживать чужой код не видя его - как лечить по фотографии родственника ;)

С одной стороны абсолютно с Вами согласен. С другой - посмотрите мой предыдущий пост. Мне хочется узнать причинно-следственную связь данного явления. Что бы в следующий раз я мог, к примеру, посмотреть в протеусе регист ХХХ и сказать, что собака зарыта "вот здесь".

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

123ksn пишет:

Кроме того, меня больше интересует академическая сторона вопроса. Т.е. есть проблема и как её решить не методом перебора или "научного тыка", а методом "квалифицированного инженера".  Это знаете, как ремонтрировать телевизор проверяя все детали.  А можно на основании пары измерений сказать, что, к примеру, не работает кадровая развертка и проверять только этот блок. С этой точки зрения, IMHO, я дал информации достаточно.

Вы искренне полагаете, что квалифицированные инженеры ремонтируют телевизоры исключительно по переписке, при этом не зная модели и не видя схемы?

Правильно - квалифицированному инженеру достаточно информации, что он - квалифицированный инженер.

PS. Кстати, здест собираются в основном не "квалифицированные инженеры", а любители, для которых Ардуино - это хобби.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

123ksn пишет:

Кроме того, меня больше интересует академическая сторона вопроса. Т.е. есть проблема и как её решить не методом перебора или "научного тыка", а методом "квалифицированного инженера".  Это знаете, как ремонтрировать телевизор проверяя все детали. 

Когда у инженера имеется схема телевизора, разработанная в соответствии с типовыми схемотехническими решениями, тогда и поиск будет типовым с проверкой определённых напряжений/сигналов в определённых точках. Но, коли инженер получает на ремонт тяп-ляп с блоками, настроенными на глазок, то он может или начинать менять всё подряд или срисовывать схему и только после этого пытаться что-то найти.

Logik
Онлайн
Зарегистрирован: 05.08.2014

Ладно бы"тяп-ляп с блоками, настроенными на глазок". А то ж блок "я немного его доработал и проект перестал работать". Может выпаял чего, может добавил, а скорей и то и то. Для не типовых решений не может быть "на основании пары измерений сказать, что, к примеру, не работает", у каждого своя специфика. Потому аналогия между ремонтом ТВ и отладкой своего кода в принципе не верна.

"Мне хочется узнать причинно-следственную связь данного явления." - угу. Это и есть цель процесса. Как токо узнаем - сразу и починим.

" Я тоже думал о 10.000. Но это ни к чему не привязать (типу данных, переполнению и т.п.)" - нет. Даже из приведенного кода видно что в 10.000 взводится Flag_PeriodToUART (закоментировать это и проверить!), правда это во второй раз. Первый был в 5.000. Наверное. Этого я явно не вижу, лога нет. Но из того, что есть, видно что некоторые действия в 10.000 происходят. Их и смотреть нужно. Но мне смотреть некуда.

А потому, давайте не торговатся. На форуме иногда находятся люди, готовые по тем или иным мотивам (от скуки например) глянуть чужую проблему за просто так. Вместо того чтоб усложнять добрым людям жизнь, лучше делали бы чего пишут. А то ведь просто перестанут отвечать, и долбитесь сами как можете. И это будет целиком справедливо. А уж срачей боятся - на форум не писать.

И еще. Обратите внимание на п.1 из #8. По аналогии - это как пригнать машину на СТО, мол глохнет зараза. А чем заправляеш? 92-м. А нужно 95-м! Из-за этого глохнет? Не факт, но одну из возможных причин, лежащих на поверхности и легко поправимых, нужно устранить прежде чем разбирать двигатель. Не нужно перегружать сириал отладочными сообщениями до такой степени что Loop в десятки раз замедлился. Посокращать их - элементарно. 

123ksn
Offline
Зарегистрирован: 24.11.2014

Большое спасибо всем откликнувшимся на проблему. Начались "праведные" речи. Поэтому что бы не портить наш конструктивный диалог нравоучениями, давайте его закончим. Решение, в том виде в котором оно интересует меня, подсказать не можете. Я понимаю, что мне никто и ничего не должен.

Сделаю как написал в первом посте - начну построчно добавлять в старый исходник изменения и смотреть на какой строке программа начнет перезагружать МК. О результатах отпишусь. Всем успехов!