Comments 20
Я не понял, у Вас обработчик прерывания окончания записи EEPROM вызывается в состоянии WFI? Если так, то вполне документированная работа, т.е. возврат в состояние WFI после вложенного прерывания.
you can set the AL bit before entering Low power mode (by executing WFI/HALT instruction). Consequently, the interrupt routine causes the device to return to low power mode., then the interrupt routine returns directly to Low power mode. The run time/ISR execution is reduced due to the fact that the register context is saved only on the first interrupt
Так Вы же сами перевели контроллер на самый низкий приоритет в обработчике EEPROM ISR, тем самым позволили другим прерываниям вмешиваться в ход обработки первого прерывания. При входе во вложенное прерывание от таймера, в стеке сохраняется регистровый контекст, по которому контроллер находится в основном процессе. При выходе из вложенного прерывания в контроллере установлен бит AL и RETI, что приводит к тому, что и описано в документации, т.е. вход в WFI.
Вопрос, зачем Вам понижать приоритет в обработчике окончания записи EEPROM, но при этом пытаться остаться в обработчике? Нестандартное решение -> нестандартное поведение.
- Workarounds #3. Вы уверены, что у Вас осталось вложенное прерывание? Может просто оно остается висячим до окончания EEPROM ISR?
2. После окончания записи байта/слова возможно нам понадобится записать следующий байт/слово. Это надо определить и инициировать следующую операцию. Несколько команд.
Для уменьшения времени пребывания в режиме запрещения прерываний вполне законно изменить текущий приоритет. И в этот момент произошло вложенное прерывание. Что тут не стандартного?
3. Проверяется, допустим, изменением состояния внешнего пина с просмотром результата на осциллографе. Либо изменением какой-либо ячейки памяти. Да, я уверен: вложенное прерывание остается.
По первому отписался ниже.
По второму, стандартно, т.е. "условно стандартно", перешли по вектору прерывания, обработали, вышли из прерывания соответствующей инструкцией. Если нужно раскидать обработку прерываний от разных источников, то выставляем соответствующие программные приоритеты. И совсем другая ситуация "условно не стандартно" когда понижают приоритет в самом прерывании. С какой целью, словить другое прерывание и обмануть логику микроконтроллера? Во всяком случае, без понимания контекста задачи трудно понять зачем такие выкрутасы. Если нужно выполнить еще какие-то операции, например инициировать запись следующего байта/слова и при этом дать возможность другим прерываниям на приоритетную обработку, то тут, как мне кажется, проще в самом прерывании окончания записи байта разрешить более приоритетные прерывания путем воздействия на механизмы запрета самих же прерываний, но никак не на статусные биты контроллера. Опять же, такой вариант исходит из того, что у Вас изначально приоритет EEPROM IRQ был самым высоким по каким-то причинам.
По третьему. Вы можете однозначно сказать, когда происходит переход по вектору вложенного прерывания, до или после "ручного" изменения битов приоритета CC? Это событие нужно отследить при разных программных приоритетах EEPROM IRQ.
Мне кажется, я начал улавливать причину такого поведения. Пока Вы разруливаете приоритет прерываний программным способом, а восстановлением состояния CC занимается IRET, то все происходит как положено. Но как только начинается несанкционированное изменение статусных битов, выполнение инструкции IRET приводит к неоднозначному поведению.
По третьему. Для своей задачи со своим конкретным камнем я нашел конкретные workarounds. Но этого нет в errata/reference/datasheet. Что стоило мне 2 недели рабочего времени. Это не нормально. Статья для того, чтобы другие не наступали на те же самые грабли. Плюс просьба проверить описанное поведение на других кристаллах семейства.
А что такое «несанкционированное изменение статусных битов»? Где в reference есть прямой запрет на изменение I1/I0 внутри ISR? Может быть мне еще запретят завершать ISR любым другим способом, кроме как по команде IRET?
Ваш живой пример прекрасно работает при указанном workaround #3, т.е. через настройку программных приоритетов. Если я правильно понял, контекст задачи заключается как раз в том, что сначала нужно выполнить очень приоритетные инструкции в прерывании, а потом идет череда второстепенных. Вот эти второстепенные, но все в том же прерывании, могут быть "отложены" на время работы с оборудованием. При этом программный приоритет прерывания настроен на самый высший уровень. Верно?
Где в reference есть прямой запрет на изменение I1/I0 внутри ISR? Может быть мне еще запретят завершать ISR любым другим способом, кроме как по команде IRET?
Не надо ерепениться. Речь не о запрете, а об отсутствии документированного поведения на все возможные действия. Ожидали одно, а получилось другое и виноват производитель. После первой убитой недели можно было бы и в службу поддержки обратиться.
Тем не менее, спасибо Вам за занимательные грабли. Будем иметь в виду. Могу по случаю проверить на STM8S003 или STM8L052C6, тем более что намечается разработка с пониженным энергопотреблением. До осциллографа надо только донести
А если попробовать сбросить AL перед включением вложенных прерываний и установить его перед выходом из прерывания, чисто ради эксперимента?
1. Для чего вообще используете WFI, задача не позволяет использовать Active-Halt?
2. Почему не хотите возвращаться к исполнению основного кода? По моему опыту это экономия на спичках в плане энергосбережения.
Из собственного опыта, я сравнивал работу одного и того-же устройства на STM8L с разными вариантами реализации энергосбережения, в том числе low power run. Так вот, наименьшее потребление показала прошивка, работающая на максимальной частоте контроллера, уходящая в Active-Halt для ожидания прерываний. При чем разница по потреблению даже с LPR была в разы!
Вот только на этой неделе занимались измерением потребления на задачке «раз в 100 мс просыпаемся, немного работаем, засыпаем». У STM32L1 оптимум оказался на частоте 2 или 4 МГц MSI.
Wait (WFI/WFE) же на STM8L нужен, если нужна работа периферии — она в Wait тактируется, в Halt нет.
1. Сохранять GCR.AL при входе в обработчик перед включением вложенных прерываний и восстанавливать его перед выходом (не забыв перед этим прерывания выключить).
2. Возвращаться в основной цикл и снова делать там WFI
Что будет лучше, сложно сказать, не зная конкретной задачи
У нас вон тоже недавно было весело. STM32L, уходим в STOP по WFI, выходим, инициализируем тактовые, восстанавливаем периферию, идём пересчитывать частоту USART — потому как есть вариант, при котором в сон уходили на одной частоте, а по выходу перестроились на другую.
И вот если у USART ножки выведены в один порт, то всё хорошо. А если в другой — то при записи в BRR тут же кровь, кишки, хардфолт.
Умом понять трудно, но выключить USART перед записью в BRR и включить сразу после помогает.
Так что в контроллерах трудно чем-то удивляться. Непродуктивно.
(2) Да фиг с этим исполнением основного кода. Просто обнаруженное поведение не описано ни в reference, ни в errata. Вот я и спросил, «это у одного меня такие глюки, или сие есть баг/фича камня?».
не описано ни в reference, ни в errata
Тут согласен, использование Activation Level и Nested Interrupts описываются в разных подразделах и их совместное использование нигде не упоминается. А чем вам не понравился Workaround #3?
P.S. olartamonov, а ты еще не любишь «arduino» в коммерческих проектах ;). Для atmel (имеется ввиду именно работа с голым железом, а не C++ обертка для чайников) пишешь, заглядывая одним глазком в datasheet, и все работает с первого раза. Когда у них крайний раз было обнаружено несоответствие описания функционированию реального железа? А STM-железо все-таки очень сырое. Несмотря на большое количество аппаратных плюшек.
WFI находится не в обработчике ISR EEPROM, а в основной программе
А какая разница, при каком значение PC и GCR была выполнена последовательность AL=1 и WFI? У вас выполняется IRET во вложенном прерывании, восстанавливается CC с I1 = 1 и I0 = 0, что при установленном AL приводит к спячке
Про безусловное засыпание при IRET с учетом только приоритета кода и без учета PC я уж вообще молчу. Просыпаться-то как будем? Восстановим регистры из стека и с таким набором продолжим обработку прерванной ISR?
Аналогичная ситуация происходит и в случае понижения приоритета кода в ISR EEPROM до любого другого значения, отличного от I1 == I0 == 1.
Ну вот теперь уже понятнее. То есть при выходе из вложенного прерывания в состояние с любым меньшим приоритетом происходит возврат в сон. Такое поведение выглядит действительно, мягко говоря, "странноватым" и как минимум должно быть обоснованным в документации. Поймите правильно, мне здесь не нравится только оговорка про "любое меньшее". Но мне вполне логичным кажется такое поведение при возврате в состояние с наименьшим приоритетом.
А по поводу PC, что Вас смущает? В спячку контроллер возвращается после выполнения RETI (при установленном AL), а значит PC должен выгрузиться из стека до остановки тактирования. При возобновлении тактирования содержимое PC вполне определенное, и именно то, которое было до входа в последнее прерывание.
del
Ошибка обработки вложенных прерываний в STM8 (не описана в errata)