Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Конфликт флагов прерываний SREG- TCCR1A.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
mogikanin
Конфликт флагов прерываний SREG- TCCR1A.
Установлено ПО: WinAVR-20100110, AvrStudio418Setup+ AVRStudio4.18SP1. Программа на AVR GCC. При загрузке регистр TCCR1A=0x02. Последней операцией идёт разрешение прерываний SREG|=(1<<SREG_I);. Пробовал и SREG=0x80; - результат один и тот же: одновременно с флагом I (7-й разряд) устанавливается так же 7-й разряд в TCCR1A. И результат становится TCCR1A=0x82. Кто-нибудь сталкивался с такой проблемой? И как она решается? На форуме уже обсуждался аналогичный вопрос с взаимовлияниями TCCR1A и SREG, но я не понял решения и ситуация там была с выходом из программы, а не во время загрузки. В загрузке я после установки SREG добавил TCCR1A=0x02; - это помогло. Но как этот дефект скажется во время работы программы? Опасаюсь.
VladislavS
Даташит:
Цитата
The I-bit can also be set and cleared by the application with the SEI and CLI instructions
Палыч
Цитата(mogikanin @ Jun 5 2011, 08:03) *
одновременно с флагом I (7-й разряд) устанавливается так же 7-й разряд в TCCR1A.

Вероятнее всего, что как только Вы разрешили прерывания глобально (бит I в SREG), то какое-то прерывание тут же и случилось... В процедуре обработки этого прерывания был установлен 7-ой бит регистра таймера TCCR1A.
mogikanin
Цитата(Палыч @ Jun 5 2011, 13:59) *
Вероятнее всего, что как только Вы разрешили прерывания глобально (бит I в SREG), то какое-то прерывание тут же и случилось... В процедуре обработки этого прерывания был установлен 7-ой бит регистра таймера TCCR1A.

В силу обстоятельств программу из Ассемблера пришлось переделывать на СИ (AVR GCC). В варианте Ассемблера такого небыло никогда. Программа тупо переделана на СИ. Т.е., порядок загрузок и инициализаций, а также все процедуры. Потому и удивляет такая ситуация. Был у меня эпизод с незаписью ЕЕПРОМ. Оказалось, что это дефекты старой версии, потому я и указал установленные версии. Я перед операцией SREG|=(1<<SREG_I); записал значения TCCR1A и сразу после неё. Именно после установки I происходит запись в TCCR1A. Т.е., вроде прерывания не успевают отработать. Поэтому, складывается впечатление, что запись в 7-й разряд SREG и TCCR1A происходит одновременно.
ARV
если вы "тупо" переделали программу на Си, не исключено, что внесли при этом ряд ошибок.
в частности, с SREG-ом в WinAVR напрямую работать нужды почти никогда не возникает, т.к. для разрешения и запрещения прерываний имеются макросы sei() и cli(). все периферийные регистры в WinAVR объявлены как volatile-переменные, поэтому оператор SREG|=(1<<SREG_I); выполняется неатомарно, что может давать странные эффекты.

используйте правильные средства - будет правильный результат.
demiurg_spb
Цитата(ARV @ Jun 6 2011, 08:38) *
поэтому оператор SREG|=(1<<SREG_I); выполняется неатомарно, что может давать странные эффекты.
Практически исключено (может кроме нулевого уровня оптимизации). SREG в SFR области и такой код превратится в атомарные инструкции SBI и CBI.
Хотя нет я погорячился. SBI и CBI адресуют лишь 32 байта, а SREG за этой границей. Так что очистка-установка битиков регистра SREG по маске в общем случае - неатомарная операция.

Также стоит покопать в сторону:
Цитата(Палыч @ Jun 5 2011, 10:59) *
Вероятнее всего, что как только Вы разрешили прерывания глобально (бит I в SREG), то какое-то прерывание тут же и случилось... В процедуре обработки этого прерывания был установлен 7-ой бит регистра таймера TCCR1A.
Палыч
Цитата(mogikanin @ Jun 6 2011, 06:00) *
...складывается впечатление, что запись в 7-й разряд SREG и TCCR1A происходит одновременно.
Хорошо бы узнать: отчего у Вас такое "складывается впечатление"? Каким образом, каким средством Вы проверяете выполнение программы? Симулятор? В "железе"? Как смотрите? Что получаете?

P.S. Хорошо бы было, если бы Вы сообщили: какой AVR применяете?
_Pasha
Цитата(demiurg_spb @ Jun 6 2011, 07:48) *
Хотя нет я погорячился. SBI и CBI адресуют лишь 32 байта, а SREG за этой границей. Так что очистка-установка битиков регистра SREG по маске в общем случае - неатомарная операция.

Вы так больше не пугайте sm.gif
Код
sei/cli set/clt sev/clv sen/cln sez/clz sec/clc
- что еще забыл? Да и ладно - смысл и так понятен - это атомарные операции.
demiurg_spb
Цитата(_Pasha @ Jun 6 2011, 09:47) *
Код
sei/cli set/clt sev/clv sen/cln sez/clz sec/clc
- что еще забыл?
Все остальные инструкции AVR:)
mogikanin
Цитата(Палыч @ Jun 6 2011, 12:20) *
Хорошо бы узнать: отчего у Вас такое "складывается впечатление"? Каким образом, каким средством Вы проверяете выполнение программы? Симулятор? В "железе"? Как смотрите? Что получаете?

P.S. Хорошо бы было, если бы Вы сообщили: какой AVR применяете?

В самом первом своём сообщении я перечислил ПО. Могу повторить:
Установлено ПО: WinAVR-20100110, AvrStudio418Setup+ AVRStudio4.18SP1. Программа на AVR GCC.
Выполнение программы проверяю на железе. В ячейку памяти пишу данные до операции, в другую - после. Потом читаю данные ячеек через интерфейс. В эти ячейки ничего попасть не может чужого. Вот так:
mem1=TCCR1A;
SREG|=(1<<SREG_I);
mem2=TCCR1A;
В результате получаю:
mem1=0x02, mem2=0x82. При отладке всегда так делаю. И всегда помогало. И сейчас помогло, когда я догадался, что в этом месте порча регистра TCCR1A. Может, я где-то неправ? Неужели между SREG|=(1<<SREG_I); и mem2=TCCR1A; программа успевает что-то сделать? Вроде логично - может. Но в таком случае как правильно инициализировать TCCR1A и флаг I, чтобы не происходила эта чепуха.
Причём, если я не сделаю перед циклом SREG|=(1<<SREG_I);, прерывания не работают вообще, так что сам флаг не устанавливается.
VladislavS
1. Смотри ассемблерный код. Чудес не бывает.
2. Использовать sei() и cli() религия не позволяет?
Палыч
Закоментируйте всё до приведенной Вами конструкции (сохранение в памяти регистров и глобальное разрешение прерываний). Сравните сохраненные значения, если они равны, то вставляйте частями закоментированные куски... Ищите где происходит "бяка".
mogikanin
Цитата(VladislavS @ Jun 6 2011, 18:12) *
1. Смотри ассемблерный код. Чудес не бывает.
2. Использовать sei() и cli() религия не позволяет?

sei() и cli() религия позволяет. Пробовал. Но на старой версии 2006. Там их нет, ПО ругалось. В новой версии 2010 не попробовал, считал что будет также. Но попробую.

Цитата(Палыч @ Jun 6 2011, 19:33) *
Закоментируйте всё до приведенной Вами конструкции (сохранение в памяти регистров и глобальное разрешение прерываний). Сравните сохраненные значения, если они равны, то вставляйте частями закоментированные куски... Ищите где происходит "бяка".

Спасибо, попробую. Но я думал, что кто-нибудь уже сталкивался с этим. Ведь была же ошибка при записи в ЕЕПРОМ. Я по рекомендации обновил версии и эта ошибка исчезла. А с конфликтом этих регистров - может у них опять ошибка?
demiurg_spb
Цитата(mogikanin @ Jun 7 2011, 07:53) *
sei() и cli() религия позволяет. Пробовал. Но на старой версии 2006. Там их нет, ПО ругалось. В новой версии 2010 не попробовал, считал что будет также. Но попробую.
На любой версии есть.
Код
#include <avr/interrupt.h>

Цитата(mogikanin @ Jun 7 2011, 07:53) *
Ведь была же ошибка при записи в ЕЕПРОМ.
Это не ошибка, а особенность. И никуда ничего не делось и не исправилось. Просто включайте brown-out detector и всё.
Цитата(mogikanin @ Jun 7 2011, 07:53) *
может у них опять ошибка?
У кого у них?
В 99,9% ошибка у Вас в голове...
_Pasha
Цитата(mogikanin @ Jun 7 2011, 06:53) *
А с конфликтом этих регистров - может у них опять ошибка?

Дядя, листинг в студию. И фсё тут.
Marian
Цитата(mogikanin @ Jun 5 2011, 07:03) *
Конфликт флагов прерываний SREG- TCCR1A.
Установлено ПО: WinAVR-20100110, AvrStudio418Setup+ AVRStudio4.18SP1. Программа на AVR GCC. При загрузке регистр TCCR1A=0x02. Последней операцией идёт разрешение прерываний SREG|=(1<<SREG_I);. Пробовал и SREG=0x80; - результат один и тот же: одновременно с флагом I (7-й разряд) устанавливается так же 7-й разряд в TCCR1A. И результат становится TCCR1A=0x82. Кто-нибудь сталкивался с такой проблемой? И как она решается? На форуме уже обсуждался аналогичный вопрос с взаимовлияниями TCCR1A и SREG, но я не понял решения и ситуация там была с выходом из программы, а не во время загрузки. В загрузке я после установки SREG добавил TCCR1A=0x02; - это помогло. Но как этот дефект скажется во время работы программы? Опасаюсь.


По тем данным, что вы предоставили, проблемы нет.
Нет кода нет подсказки.
Нажмите для просмотра прикрепленного файла

Код выложите, а то я сильно сомневаюсь, что 7-й разряд в TCCR1A самопроизвольно устанавливается. И проц какой не написали.
mogikanin
Цитата(demiurg_spb @ Jun 7 2011, 11:28) *
На любой версии есть.
Код
#include <avr/interrupt.h>

Это не ошибка, а особенность. И никуда ничего не делось и не исправилось. Просто включайте brown-out detector и всё.
У кого у них?
В 99,9% ошибка у Вас в голове...

<avr/interrupt.h> - это я не забыл.
"Это не ошибка, а особенность." - но у меня факт - записи в ЕЕПРОМ небыло. Обновил версии не меняя программы - и она заработала. А про эту "особенность" я не выдумал - она обсуждалась на сайте в прошлом году. Просто я узнал об этом месяц назад. И "brown-out detector" здесь ни при чём.
"В 99,9% ошибка у Вас в голове..." - хоть и грубо, но приходится согласиться.
Цитата(Marian @ Jun 7 2011, 18:27) *

Контроллер ATmega16. Листинг пока не вижу смысла высылать - это много. Я попробую сделаю чисто тестовый проект и, если ошибка повторится, - вот его и вышлю. А всю программу - никому это не нужно. У меня там инициализация USART, TIME1(TCCR1A,TCCR1B), INT1, INT2, и последняя операция - установка этого главного флага.
Палыч
Цитата(mogikanin @ Jun 8 2011, 06:13) *
Я попробую сделаю чисто тестовый проект и, если ошибка повторится, - вот его и вышлю. А всю программу - никому это не нужно. У меня там инициализация USART, TIME1(TCCR1A,TCCR1B), INT1, INT2, и последняя операция - установка этого главного флага.
Делать "чисто тестовый проект" - вряд ли нужно. Нужно лишь локализовать ошибку. Для чего нужно закоментировать инициализацию устройств, и сравнивать результат "работы" программы по изменению регистра таймера до и после разрешения прерываний. Нужно найти: инициализация какого устройства приводит к этому эффекту? Ну, а потом: искать в участках программы работы с этим устройством ошибку... Если самостоятельно не найдете - выкладывайте код работы с устройством на форум.
mogikanin
Цитата(Палыч @ Jun 8 2011, 12:51) *
Если самостоятельно не найдете - выкладывайте код работы с устройством на форум.

Хорошо, попробую. А если сам найду ошибку - стоит ли всех этим беспокоить?
Мои затычки в программе (повтор записи кода в регистр после установки SREGI) помогли, но причину пока не нашёл. Есть подозрение на INT2, в котором есть команда записать в TCCR1A в 7-й разряд "1". Но по программе это должно происходить далеко позже. Мне кажется, что отладчик будет писать правильно, а железо - нет. Скорее всего я сам создал такую очерёдность инициализаций, которая приводит к этой ошибке. Но пока не могу найти. Порт PORTB2 (вход INT2) я устанавливаю на приём с подтяжкой. Может при включении питания это воспринимается как прерывание? Но и команда записать в TCCR1A в 7-й разряд "1" проходит не во время инициализации, а при определённых условиях, которых в это время нет.
Мне важно было знать: сталкивался ли кто с этой проблемой? Поскольку никто - правильнее считать, что это не дефект СИ-компилятора, а моей программы. Где-то я с ней грубо обошёлся.
SysRq
Цитата(mogikanin @ Jun 9 2011, 08:22) *
...это воспринимается как прерывание?
А вы в инициализации флаг сбросьте перед разрешением прерывания по нему.
Marian
Цитата(mogikanin @ Jun 9 2011, 07:22) *
Хорошо, попробую. А если сам найду ошибку - стоит ли всех этим беспокоить?
Есть подозрение на INT2, в котором есть команда записать в TCCR1A в 7-й разряд "1". Но по программе это должно происходить далеко позже.

Время на проверку этого пять минут, за комментировал запись в TCCR1A в 7-й разряд "1" в INT2 да и проверил.
mogikanin
Цитата(Marian @ Jun 10 2011, 00:22) *
Время на проверку этого пять минут, за комментировал запись в TCCR1A в 7-й разряд "1" в INT2 да и проверил.

Нашёл ошибку в своей программе. На это ушло далеко не 5 минут (низкая квалификация). Тему можно считать закрытой. Спасибо всем за помощь!
Может, кому пригодится:
1) Заблуждение: прерывание INT2 установлено на смену фронта, поэтому при включении питания прерывание не должно срабатывать(полагал, что сигнал подтяжки означает не фронт сигнала, а просто сигнал), а оно срабатывает. В этом прерывании идёт обработка сигналов (в моей программе) и разрешение (включение) бита 7 при этом не должно происходить, потому и не мог понять ошибку.
2) Ошибка в программе - должно было быть if (~flag77 & (1<<4)), а у меня небыло знака инверсии (if (flag77 & (1<<4))). Т.е. я считал, что операция запрещена, а она разрешалась.
Помогло отсутствие сообщений об аналогичной ошибке, что означало наличие ошибки именно в моей программе, а не в компиляторе.
demiurg_spb
Цитата(mogikanin @ Jun 10 2011, 09:37) *
if (~flag77 & (1<<4))
Бред какой-то.
Вы чего этим хотите добиться?
Палыч
Цитата(demiurg_spb @ Jun 10 2011, 15:43) *
Бред какой-то.
Почему же - бред? Наверное, нужно что-то выполнить, если соответствующий разряд флага равен нулю.
mogikanin
Цитата(Палыч @ Jun 10 2011, 18:58) *
Почему же - бред? Наверное, нужно что-то выполнить, если соответствующий разряд флага равен нулю.

Спасибо Палыч за понимание. Этот бит как раз и отвечал за установку бита 7 (разрешение подклюяения порта к ШИМ). Я был уверен, что запрещаю, а на самом деле разрешал. Правильное было утверждение, что как только я разрешал все прерывания, оно тут же и выполнялось.
demiurg_spb
Цитата(Палыч @ Jun 10 2011, 15:58) *
Почему же - бред? Наверное, нужно что-то выполнить, если соответствующий разряд флага равен нулю.

Потому что приоритет ~ выше и будет 3 операции, сначала битовая инверсия, потом наложение маски и проверка на не ноль результата.
Многовато не находите?
Автор индусского кода видимо хотел этого
Код
if (!(flag77 & (1<<4))) {}
Не стоит смешивать битовые и булевые операции...
Да, предлагаю назвать переменную более красиво - flag666, чтоб наверняка..
Палыч
Цитата(demiurg_spb @ Jun 13 2011, 20:35) *
Многовато не находите?
Автор индусского кода видимо хотел этого...
Да, не оптимально написано. Ну, низкая квалификация у человека, и он это не отрицает. Опыт - дело времени...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.