шумные выходные линии при пробуждении ото сна

Использование кода, подобного этим примерам, из AVR

https://www.microchip.com/webdoc/AVRLibcReferenceManual/group__avr__sleep.html

Моя программа заставляет мой Adafruit Feather 32u4 часто переходить в спящий режим. Когда прошивке нечего делать, она будет спать около 75% времени. Обычно после нескольких часов работы на ЖК-дисплее появляются повреждения. Время, прошедшее до повреждения, не является детерминированным.

Я полагаю, что когда он спит или выходит из спящего режима, процессор отправляет мусор в модуль ЖК-дисплея через линии SPI (последовательные). У меня нет осциллографа, чтобы это наблюдать, но проблема, похоже, исчезнет, если я закомментирую код сна.

Описание ЖК-модуля Adafruit ST7565 находится по этой ссылке

https://www.adafruit.com/product/250.

Мой код настройки Arduino, относящийся к спящему режиму, таков:

cli(); // здесь начинается атомарная операция
WDTCSR = bit(WDCE) | bit(WDE); // вход в режим очень кратких изменений
WDTCSR = bit(WDP2); // прескалер без режима сброса, 1001 означает 8 секунд, 0101 означает 0,5 секунды, 0100 означает 0,25 секунды, 0011 означает 0,125 секунды
WDTCSR = bit(WDIE); // используем режим прерывания, потому что нам не нужен сброс, вызванный WDT
sei(); // глобальное разрешение прерываний
set_sleep_mode(SLEEP_MODE_PWR_DOWN);

Мой код сна в цикле Arduino адаптирован с веб-страницы AVR и вызывается, если прошивка не занята, следующим образом:

cli(); // здесь начинается атомарная операция
sleep_enable();
sei();
sleep_cpu();
sleep_disable();

Сторожевой ISR при пробуждении представляет собой пустую функцию, а именно:

ISR(WDT_vect) // это необходимо, чтобы избежать сброса
{ // здесь нет кода
}

У меня есть немного других доказательств того, что некоторые строки не контролируются, когда процессор просыпается. Доказательства получены от моих вращающихся энкодеров. Иногда я вижу ложную активность кодировщика, когда процессор просыпается, и я устранил эту проблему, добавив некоторый «код устранения дребезга» в сторожевой ISR. Я также проверяю, что линии энкодера используют внутренние подтягивающие резисторы процессора. Обратите внимание, что у меня уже есть код устранения дребезга для кодировщиков, предназначенный для фактического устранения дребезга при фактическом прикосновении к кодерам. Дополнительный «код устранения дребезга» в сторожевом ISR предназначен для ситуации, когда я даже не прикасаюсь к энкодерам, но процессор просыпается и линии зашумлены. «Код устранения дребезга» кодировщика не отображается во фрагменте кода сторожевого таймера ISR, поскольку он не имеет отношения к моей проблеме с ЖК-дисплеем.

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

Редактировать: я попытался решить эту проблему, установив высокий уровень выбора активного нижнего чипа ЖК-дисплея перед сном, а затем вернув линию после пробуждения (в сторожевом ISR). Это привело к тому, что отображение стало очень медленным. Я обновляю дисплей раз в секунду, и кажется, что он обновляется только раз в 2 или 3 секунды. Я не анализировал, несовместимо ли мое «прямое вмешательство» с библиотекой Adafruit для этого ЖК-дисплея.

Библиотека ЖК-дисплеев: https://github.com/adafruit/ST7565-LCD

Платы как на фото. На плате энкодера имеются 2 подключенных энкодера и 2 неиспользуемых энкодера. Плата энкодера расположена на куске пенопласта толщиной 3 мм и прикреплена к столу. Макет крепится к столу с помощью двухсторонней пенопластовой ленты, которая, кажется, входит в стандартную комплектацию этого изделия.

picture Приложение: учитывая ответ Ника Гаммона, я попробую следующее, чтобы посмотреть, устранена ли проблема. Поскольку коррупция не является детерминированной, может пройти много часов или дней, прежде чем я сформирую мнение.

  cli(); // здесь начинается атомарная операция
  WDTCSR = bit(WDCE); // вход в режим краткого изменения
  WDTCSR = bit(WDIE) | bit(WDP2); // 1001=8 с, 0101=0,5 с, 0100=0,25 с, 0011=0,125 с
  sei(); // глобальное разрешение прерывания
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 

Менее чем через 10 часов на ЖК-дисплее произошло повреждение. Я протестирую следующее.

  cli(); // здесь начинается атомарная операция
  WDTCSR = bit(WDCE) | bit(WDE); // вход в режим краткого изменения
  WDTCSR = bit(WDIE) | bit(WDP2); // 1001=8 с, 0101=0,5 с, 0100=0,25 с, 0011=0,125 с
  sei(); // глобальное разрешение прерывания
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 

После нескольких часов вышеописанное не удалось.

, 👍0


1 ответ


Лучший ответ:

2
WDTCSR = bit(WDCE) | bit(WDE); // вход в режим очень кратких изменений
WDTCSR = bit(WDP2); // прескалер без режима сброса, 1001 означает 8 секунд, 0101 означает 0,5 секунды, 0100 означает 0,25 секунды, 0011 означает 0,125 секунды
WDTCSR = bit(WDIE); // используем режим прерывания, потому что нам не нужен сброс, вызванный WDT

Ваш код, приведенный выше, не выполняет прерывание WDT каждые 0,25 секунды, как вам хотелось бы, потому что вы назначаете (а не ИЛИ) в третьей строке. Это означает, что все WDP0/WDP1/WDP2?WDP3 будут равны нулю, что означает, что сторожевой таймер будет срабатывать каждые 16 мс.

Из-за этого отображение стало очень медленным.

Я не удивлюсь, если вы будете прерывать каждые 16 мс.


У меня есть и другие доказательства того, что некоторые строки не контролируются при пробуждении процессора.

Строки должны оставаться такими, какими они были установлены, когда процессор находится в спящем режиме. Было бы не очень полезно спать, если бы процессор во время сна начал выдавать случайный мусор. Я не могу комментировать дальше, поскольку вижу только часть вашего кода.

,

Спасибо. Мой комментарий будет дополнением к вопросу., @H2ONaCl

Вероятно, вы были правы, сказав, что проблема не вызвана сном. Укоротив провода, идущие к дисплею, я смог проработать более 50 часов, не заметив повреждений дисплея, и 50 часов — это беспрецедентно., @H2ONaCl