1kvi1 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Добрый день! Возникла следующая интересная проблема. По ходу выполнения прошивки в какой то момент происходит зацикливание программы на прерывании от USART1. То есть выполняется запуск обработчика прерываний с частотой примерно 100 кГц. Основная программа успевает сделать несколько инструкций после чего снова происходит прерывание. При этом если остановить обработку прерывания отладчиком и походить по инструкциям нормальный ход программы восстанавливается. Прерывания разрешены только на прием, флаг готовых данных не взведен. В регистре NVIC->ICSR указывается что активное прерывание от usart1. С чем может быть связанно такое поведение? Осциллографом контролировал линию - стабильная единица на обоих линиях. Стабильно повторяется. Прерывания по приему не запрещается и разрешено постоянно. void USART1_IRQHandler (void) { VD3R_ON; VD3G_ON; if (USART_GetITStatus(USART1,USART_IT_TXE)) { // USART_ClearITPendingBit(USART1,USART_IT_TXE); } if (USART_GetITStatus(USART1,USART_IT_RXNE)) { // USART_ClearITPendingBit(USART1,USART_IT_RXNE); unsigned char receive_char=USART_ReceiveData(USART1); if (!modemmode) { } VD3R_OFF; VD3G_OFF; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Думаю что это связано с тем что запросы на прерывания по приёму RXNE is auto-clr by reading data_reg и что запросы на прерывания на передачу ТXE is auto-clr by writing data_reg И что если вам нечего больше посылать нужно выключать прерывание передатчика принудительно. Ещё могу подметить что нужно первым делом считывать регистр статуса в локальную переменную и её уже анализировать, ибо может так статься что прочитанный позже повторно статус не будет иметь никакого отношения к статусу текущего байта (в смысле флагов ORE, FE, NE). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба ТО что флаги автоматически сбрасываются - это мне известно, учел - и за комментировал их сброс. Другое дело что чтение происходит лишь после анализа флага. Почему может пере запускаться прерывание если флаги состояния для которых разрешено прерывание все сброшены? Прерывания на передачу сброшены. Флаги TC TXE взведены, но прерывание отключено по ним. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vptr 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба Добрый день! Возникла следующая интересная проблема. По ходу выполнения прошивки в какой то момент происходит зацикливание программы на прерывании от USART1. То есть выполняется запуск обработчика прерываний с частотой примерно 100 кГц. Основная программа успевает сделать несколько инструкций после чего снова происходит прерывание. ... не любит STM чтобы использовали код не так, как в их примерах)). Заметил тоже самое с другими прерываниями. Например с таймером, вот такой код работает нормально: void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерывания } } а теперь для теста добавим пару переменных void TIM4_IRQHandler(void) { CountTest1++; if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерывания CountTest2++; } } В этом случае все рассыпается, переменная CountTest1 будет постоянно быстрее накапливаться, чем переменная CountTest2. Это говорит о том, что void TIM4_IRQHandler(void) вызывается намного чаще, чем планировалось. Но вот такой код: void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерывания CountTest2++; } CountTest1++; } работает нормально и CountTest1 всегда равна CountTest2. Получается, что вставка кода до строки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) все ломает. Это одинаково проявляется на STM32F207 и STM32F407. Для эксперимента пробовал добавить GPIOC->ODR ^= GPIO_Pin_13; и посмотреть осциллографом длительность на GPIO_Pin_13. Получается полный хаос. 150 мс прерывания работают как положено раз в 1 мс (таймер настроен на 1 мс), потом на 150 мс висит 0 на GPIO_Pin_13. Может зависнуть на 150 мс и с 1 на выходе GPIO_Pin_13. void TIM4_IRQHandler(void) { GPIOC->ODR ^= GPIO_Pin_13; //индицируем прерывание для отладки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерывания CountTest2++; } } опять же, если GPIOC->ODR ^= GPIO_Pin_13, добавить после строки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET), то все оживает и работает как положено. Изменено 24 ноября, 2011 пользователем vptr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба не любит STM чтобы использовали код не так, как в их примерах)). Я бы сделал другой вывод: их примеры не самые удачные, раз добавление пары команд всё рушит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
andrewlekar 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба А по-моему никто ничего не рушит, а просто прерывание вызывается по каким-то причинам чаще, чем ожидает автор. Для того, чтобы выяснить причину, нужно или курить мануалы, или делать так как написано в библиотеке. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vptr 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба да и обработка прерывания завершается TIM_ClearITPendingBit(TIM4, TIM_IT_Update) все как в примерах void TIM4_IRQHandler(void) { GPIOC->ODR ^= GPIO_Pin_13; //индицируем прерывание для отладки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерыания CountTest2++; TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } } Изменено 24 ноября, 2011 пользователем vptr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба Возможно, это то, что называется "spurious interrupt". Просто у других производителей это документировано, а у STM - обойдено в библиотеках. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба да и обработка прерывания завершается TIM_ClearITPendingBit(TIM4, TIM_IT_Update) все как в примерах void TIM4_IRQHandler(void) { GPIOC->ODR ^= GPIO_Pin_13; //индицируем прерывание для отладки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { //здесь обработчик прерыания CountTest2++; TIM_ClearITPendingBit(TIM4, TIM_IT_Update); } } В форуме здесь, а также на форуме ST, было упомянуто вообще-то для всех Кортексов (поищите сами), что при сбросе флагов прерываний непосредственно перед выходом из ISR, возможен повторный вызов ISR по причине конвейера и особенностей доступа по внутренним шинам. Поэтому перенесите TIM_ClearITPendingBit(TIM4, TIM_IT_Update); в начало ветви обработки, то есть поместив рабочие инструкции между сбросом флага и выходом из ISR. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба В форуме здесь, а также на форуме ST, было упомянуто вообще-то для всех Кортексов (поищите сами), что при сбросе флагов прерываний непосредственно перед выходом из ISR, возможен повторный вызов ISR по причине конвейера и особенностей доступа по внутренним шинам. Поэтому перенесите TIM_ClearITPendingBit(TIM4, TIM_IT_Update); в начало ветви обработки, то есть поместив рабочие инструкции между сбросом флага и выходом из ISR.Познавательно. А сколько тактов интересно нужно чтобы всё успело всосаться? И почему-бы писателям этой либы сразу было не засунуть в ClearITPendingBit нужное кол-во нопов, чтоб мозги не компостировать никому.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 · Жалоба "spurious interrupt" - да был такой опыт с nxp arm7. Сейчас как раз вспомнил как не мог разобраться с причинами глюков. Проверил документацию для ядра Cortex-M3 на предмет "spurious interrupt". Ничего не нашел - где можно еще прочитать про тонкости работы NVIC? По всем признакам это как раз "spurious interrupt" - причин для их вызова нет, но они есть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба Познавательно. А сколько тактов интересно нужно чтобы всё успело всосаться? И почему-бы писателям этой либы сразу было не засунуть в ClearITPendingBit нужное кол-во нопов, чтоб мозги не компостировать никому.... Вот тут кое-что упоминается, в частности: As Andrew noted before, the reason is that this wouldn't be an erratum. It is a feature inherent in the architecture. I'll spare you the details, but simply put, Cortex-M3 has two independent bus interfaces for instructions and data respectively. Your memory access is using the data port (and waits for the APB bus cycle to finish), while the instruction port keeps fetching more code which gets executed. The ISR return might execute before the data bus access has completed, so NVIC thinks that the (still) active IRQ was a new one. Изменено 24 ноября, 2011 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vptr 0 24 ноября, 2011 Опубликовано 24 ноября, 2011 (изменено) · Жалоба В форуме здесь, а также на форуме ST, было упомянуто вообще-то для всех Кортексов (поищите сами), что при сбросе флагов прерываний непосредственно перед выходом из ISR, возможен повторный вызов ISR по причине конвейера и особенностей доступа по внутренним шинам. Поэтому перенесите TIM_ClearITPendingBit(TIM4, TIM_IT_Update); в начало ветви обработки, то есть поместив рабочие инструкции между сбросом флага и выходом из ISR. спасибо, судя по всему в этом и есть причина вот этот код рабочий void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update);// если вызывать позже, то возможен хаос //здесь обработчик прерыания CountTest2++; ... } } Если TIM_ClearITPendingBit(TIM4, TIM_IT_Update) вызывать позже в обработчике прерывания (причем не сразу, а так через несколько команд), то наступает описанный выше хаос. В общем сам виноват, в примерах от STM так и сделано, сперва if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET), потом TIM_ClearITPendingBit(TIM4, TIM_IT_Update) и только после этого код обработки прерывания причем даже код ниже становится рабочим, но понятно что так делать нельзя, т.к. любые действия до TIM_ClearITPendingBit(TIM4, TIM_IT_Update); не есть хорошо void TIM4_IRQHandler(void) { GPIOC->ODR ^= GPIO_Pin_13; //индицируем прерывание для отладки if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update);// если вызывать позже, то возможен хаос //здесь обработчик прерывания CountTest2++; } } Изменено 24 ноября, 2011 пользователем vptr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба и только после этого код обработки прерывания причем даже код ниже становится рабочим, но понятно что так делать нельзя, т.к. любые действия до TIM_ClearITPendingBit(TIM4, TIM_IT_Update); не есть хорошоДумаю что это уже не важно. Главное чтобы ClearITPendingBit физически успел выполниться до ret. Все остальные измышления ИМХО не имеют под собой основания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 32 25 ноября, 2011 Опубликовано 25 ноября, 2011 · Жалоба Думаю что это уже не важно. Главное чтобы ClearITPendingBit физически успел выполниться до ret. Все остальные измышления ИМХО не имеют под собой основания. А не поможет тут использование инструкций-барьеров, чтобы гарантировать выполнение? А так, вообще-то, да - грабли конкретные. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться