Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Сохранение SREG
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
paskal
У меня программа принимает некоторый пакет байт по UARTу, затем шлет ответ. И прием и отправку делаю по прерываниям. При этом отсылаемый пакет иногда дублируется. Если же в основной программе после разрешения прерывания передатчика вставить паузу не менеее длины посылки, то работает идеально.
Напрашивается вывод что в обработчике прерывания по передаче меняется SREG, и цикл ожидания по команде BRNE сваливается на передачу еще одного пакета.
Всвязи с этим чайницкий вопрос. А SREG в обработчике сохраняется? И если нет, то как его сохранить?
SasaVitebsk
Если вы про Си, то сохраняется.
А вообще ничего не понятно. Ни компилятор не указали ни контроллер ни язык....
Высасываете предположения чисто из пальца.
paskal
Цитата(SasaVitebsk @ Apr 2 2010, 21:34) *
Если вы про Си, то сохраняется.
А вообще ничего не понятно. Ни компилятор не указали ни контроллер ни язык....
Высасываете предположения чисто из пальца.

На ассемблере, среда - avrstudio, чип - mega128.
ILYAUL
Цитата(paskal @ Apr 2 2010, 23:01) *
На ассемблере, среда - avrstudio, чип - mega128.

Ну например так
В начале программы.
.DEF SaveSREG =R(0...31)

А прерывании
in SaveSREG,SREG
..............................

при выходе

out SREG,SaveSREG

Но похоже дело в другом.
Но нужен код - выложите плиз
V_G
Цитата(ILYAUL @ Apr 3 2010, 06:17) *
.DEF SaveSREG =R(0...31)

А прерывании
in SaveSREG,SREG
..............................

при выходе

out SREG,SaveSREG


Если в прерывании меняется SREG, то дело именно в этом. Я во всех прерываниях сохраняю не только статусный регистр, но и пишу в стек сохраненное значение (на случай вложенных прерываний)

CODE
in SaveSREG,SREG
push SaveSREG
..............................

pop SaveSREG
out SREG,SaveSREG
ILYAUL
Цитата(V_G @ Apr 3 2010, 05:23) *
.........(на случай вложенных прерываний)


Не понял , а зачем? Во вложенном прерывании вы просто опять переписываете SREG в SaveSreg при возврате из него оно вернёт Вам предыдущий SREG, а уж выход из первого по счёту прерывания или подпрограммы - вернёт Вам начальный.
Зачем тратить стек и время? Тогда уж Push SREG ...... pop SREG

Цитата
Если в прерывании меняется SREG

Не спорю это одна из причин. Он обязан менятся , если только не просто вошли и тут же вышли. Поэтому и попросил код
defunct
Цитата(ILYAUL @ Apr 3 2010, 16:55) *
Не понял , а зачем? Во вложенном прерывании вы просто опять переписываете SREG в SaveSreg при возврате из него оно вернёт Вам предыдущий SREG, а уж выход из первого по счёту прерывания или подпрограммы - вернёт Вам начальный.


?! Это как так? В одну и ту же ячейку два раза записать разные значения, и вы надеетесь что потом сможете оба значения воcстановить?

Цитата
Тогда уж Push SREG ...... pop SREG

И что это за Push SREG? SREG в AVR находится в I/O space.
push/pop работает только с регистрами R0..R31.

V_G привел абсолютно верный пример для вложенных прерываний.
ILYAUL
Цитата
И что это за Push SREG? SREG в AVR находится в I/O space.
push/pop работает только с регистрами R0..R31.
Да "погорячился" конечно in и out

Попробывал в код приведённый ниже ,вставить код V_G дабы избавиться от
Код
ldi    temp,1<<RXCIE1|0<<UDRIE1|1<<RXEN1|1<<TXEN1
    sts UCSR1B,temp

И соответсвенно разрешил вложенное прерывание в данном случае , это стал приёмник.
Т.е , так как первый байт передачи пролетает мимо буфера передатчика сразу в сдвиговый регистр т.е передача начинается "мгновенно" и только 2- ой "застревает" в буфере , то по идее разрешив прерывание приёмника мы должны при передаче 2 байта уйти на обработку приемника , где прервыания запрещены флаг (I)=0 и затем вернутся в передатчик - не проконало .

CODE
;**************************************************
;* ;;/Передача битов команд;;* *
;**************************************************
USART1_UDRE:
push temp ; Заталкиваем в стек temp
in SaveSREG,SREG ; SREG
push count ; счётчик
push rab ; rab
;+ Запрещаем прерывание UDRE, что бы избавиться от двойной буферизации
ldi temp,1<<RXCIE1|0<<UDRIE1|1<<RXEN1|1<<TXEN1
sts UCSR1B,temp
;+ передатчика , иначе возникает ошибка при приёме данных.
ld temp,Y ;/ Получаем байт для отсылки
sbrc Flags,fl_ByteEND;- Проверяем, был отослан весь байт?
rjmp MoveTX ;/ Нет - продолжаем пересылку бит
cpi temp,ResetDS18 ;| Сравниваем - полученный новый байт c SF0
breq SendReset ;| Равно - на формирование RESET
MoveTX:
lsr temp ;| Сдвигаем temp
st Y,temp ;/ Возвращаем байт
brcc Resetrab ;| Проверяем флаг С
ldi rab,Full ;+ Установлен - выводим (1)
rjmp SendToDS
Resetrab:
mov rab,zero ;+ Сброшен - выводим (0)
SendToDS:
sts UDR1,rab ;| Загружаем данные
EndTX:
sbr Flags,fl_ByteEND
pop rab ; Выталкиваем из стека rab
pop count ; счётчик
out SREG,SaveSREG ; SREG
pop temp ; temp
reti

;**************************************************
;* ;;/Приём битов команд;;* *
;**************************************************
USART1_RXC:
push temp ; Заталкиваем в стек temp
in SaveSREG,SREG ; SREG
push count ; счётчик
push rab ; rab
;+ Разрешаем прерывание UDRE
ldi temp,1<<RXCIE1|1<<UDRIE1|1<<RXEN1|1<<TXEN1
sts UCSR1B,temp
ld rab,Y
lds temp,UDR1 ;+ Считываем данные
cpi temp,Full ;| Получена единица
breq WriteOneRX ;| Переходим на запись (1) в старш. бит
rjmp SaveDataDS16 ;| Нет - запись (0)
WriteOneRx:
sbr rab,1<<MsbOne ;-Устанавливаем (1) в старшем бите
SaveDataDS16:
st Y,rab ;+Записываем значение
mov count,SaveBitcount;/Загружаем количество бит
inc count ;| Прибавляем счётчик
cpi count,0x08 ;- Восемь бит обработано
breq CheckBufDS18 ;| Да - переходим на проверку счётчика байт
mov SaveBitcount,count;| Нет - сохраняем счётчик бит
rjmp EndRX ;+ И выходим из прерывания
CheckBufDS18:
cpi rab,ToConvTermo ;| Ищем команду ToConvTermo
brne ForwardCheck ;| Не она идём дальше
CheckPinRX: ;/ По идее конверт. должна закончиться до этой проверки,
sbis PIND,PIND2 ;/ но если на входе (0) конвертация не закончена
rjmp CheckPinRX ;/ Тогда - ждём
ForwardCheck:
cbr Flags,1<<fl_ByteEND;
clr SaveBitcount ;/ Очищаем счётчик бит
adiw Y,0x01 ;/ Добавляем адрес буфера
inc SaveBufCount ;/ Добавляем счётчик буффера
mov count,SaveBufCount;| Загружаем счётчик буфера
cpi count,Full ;| Сравниваем - это последний принимаемый байт
brne EndRX ;+ Нет - выходим из прерывания
clr SaveBufcount ;- Очищаем счётчик бит
ldi temp,0<<RXCIE1|0<<UDRIE1|0<<RXEN1|0<<TXEN1
sts UCSR1B,temp ;/ Запрещаем работу USART1
ldwi Y,DATADS18 ;+ загрузка в YH:YL адреса буфера DS18B20
sbr Flags,1<<fl_ReadyDS18 ;+ Устанавливаем флаг Данные готовы
EndRX:
pop rab ; Выталкиваем из стека rab
pop count ; счётчик
out SREG,SaveSREG ; SREG
pop temp ; temp
reti
demiurg_spb
Вы не поняли, так делать плохо:
Цитата(ILYAUL @ Apr 4 2010, 01:34) *
Код
USART1_UDRE:        
        push    temp; Заталкиваем в стек temp
        in    SaveSREG,SREG; SREG
        push    count; счётчик
        push    rab; rab
;+ Запрещаем прерывание UDRE, что бы избавиться от двойной буферизации
        ldi    temp,1<<RXCIE1|0<<UDRIE1|1<<RXEN1|1<<TXEN1
        sts    UCSR1B,temp
;+ передатчика , иначе возникает ошибка при приёме данных.

        pop    rab; Выталкиваем из стека rab
        pop    count; счётчик
        out    SREG,SaveSREG; SREG
        pop    temp; temp
        reti

Вот так нормально (и не надо никакие прерывания запрещать):
Код
        push    temp
        in    temp,SREG
        push    temp
        push    count
        push    rab

        pop    rab
        pop    count
        pop    temp
        out    SREG,temp
        pop    temp
        reti
ILYAUL
Цитата(demiurg_spb @ Apr 4 2010, 22:41) *
Вы не поняли, так делать плохо:


Я уже посчитал - V_G прав.

Есть у меня вот такие макросы их и подставил впредыдущем посте - не прокатило. Всё равно пришлось запрещать UDRE

Код
;***************************************
.macro    BeginInt
    push    Count
    push    ZH
    push    ZL
    push    rab
    push    temp
    in      SaveSREG,SREG
    push    SaveSREG
    push    CopySRAM
.endm
;***************************************
;-                 
;***************************************
.macro    EndInt
    pop    CopySRAM
    pop    SaveSREG
    out    SREG,SaveSREG
    pop    temp
    pop    rab
    pop    ZL
    pop    ZH
    pop    Count
.endm
;***************************************
Палыч
Цитата(ILYAUL @ Apr 4 2010, 23:14) *
Есть у меня вот такие макросы их и подставил впредыдущем посте - не прокатило.

Прежде чем выполнить команду "in SaveSREG,SREG" регистр SaveSREG желательно сохранить с стеке (как в примере у demiurg_spb), и соответственно восстановить этот регистр по окончанию прерывания.
V_G
Цитата(Палыч @ Apr 5 2010, 16:44) *
Прежде чем выполнить команду "in SaveSREG,SREG" регистр SaveSREG желательно сохранить с стеке (как в примере у demiurg_spb), и соответственно восстановить этот регистр по окончанию прерывания.

В общем случае - да, но я лично регистр для сохранения статуса в основной программе не использую, только в обработчиках прерываний.
ILYAUL
Но в случаях без вложенных прерываний волне возможно обойтись и in savesreg, sreg и соответствеено out .... Правильно ?
Палыч
Цитата(ILYAUL @ Apr 5 2010, 09:59) *
Но в случаях без вложенных прерываний волне возможно обойтись и in savesreg, sreg и соответствеено out .... Правильно ?
Т.е. Вы хотите обойтись без сохранения/восстановления SREG в прерываниях? Ни в коем случае!

Или: вопрос был о том, нужно ли всё-же сохранять регистр savereg? Если этот регистр предназначен исключительно для сохранения SREG и для других целей не используется нигде, то - да, можно его не сохранять; но в противном случае - сохранять/восстанавливать обязательно.
ILYAUL
Цитата(Палыч @ Apr 5 2010, 11:52) *
Т.е. Вы хотите обойтись без сохранения/восстановления SREG в прерываниях? Ни в коем случае!

Или: вопрос был о том, нужно ли всё-же сохранять регистр savereg? Если этот регистр предназначен исключительно для сохранения SREG и для других целей не используется нигде, то - да, можно его не сохранять; но в противном случае - сохранять/восстанавливать обязательно.

Да имено так , я сохраняю в отдельном регистре , предназначенный именно под SREG и конечно для других целей его не использую.
В приведённом мною коде ( огрызок ) , нет ещё одного прерывания , которое используется в программе , но несмотря на то что , я не толкаю SAVESREG в стек , данные возвращаются всегда коректно. Поэтому и полемика.
Поэтому и не видел смысла пушить его. Хотя надо отметиь , что вложенных прерываний в программе нет.
V_G
Цитата(ILYAUL @ Apr 5 2010, 21:58) *
Хотя надо отметиь , что вложенных прерываний в программе нет.

Ну, в общем-то в мегах все остальные прерывания запрещаются при обработке прерываний. Так что если вы насильно не поместите инструкцию SEI в код, вложенных прерываний не будет.
Другое дело - Xmega, где имеется механизм приоритетов прерываний, и о вложенных прерываниях надо заботиться, в том числе грамотной расстановкой приоритетов.
paskal
Итак, все действительно разрешилось сохранением SREG. Глюк полностью исчез.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.