Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ATmega 16L проблема с UART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
ProfessorBraz
Выручай всезнающий Олл!

ATmega 16L проблема с UART, а именно после посылки всего, когда буфер уже пустой возвращается из интерапта на начало программы (фактически рестарт). Код прерывания
Код
ISR(USART0_UDRE_INTERRUPT)
{
    uint8_t temp_tail;
    
    if ( USART0_TX_Head != USART0_TX_Tail)                            
    {
        temp_tail = (USART0_TX_Tail + 1) & USART_TX_BUFFER_MASK;    
        USART0_TX_Tail = temp_tail;                                    
        USART0_UDR = USART0_TX_Buffer[temp_tail];                
    }
    else                                                       {                                                    
        USART0_UCSRB &= ~(1<<USART0_UDRIE);                            
        USART0_Enable_Int_Status = 1;
    }
}


Что я делаю не так. При просмотре в Студии в режиме ассемблега, видно что в переходе на прерывание все пакуется в стек, потом также аккуратно распаковывается, и возвращается по команде RTI, но почемуто в старт? help.gif

Може кто с таким эффектом сталкивался?
galjoen
Цитата(ProfessorBraz @ Apr 17 2008, 15:31) *
видно что в переходе на прерывание все пакуется в стек, потом также аккуратно распаковывается, и возвращается по команде RTI, но почемуто в старт? help.gif

Не понял - вы увидели, что правильный адрес возврата в стеке лежит, а возвращается в 0? Или адрес возврата никто в стек и не клал? Что значит "в переходе на прерывание"?
Палыч
ИМХО, стек переполнился.
galjoen
Цитата(Палыч @ Apr 17 2008, 15:52) *
ИМХО, стек переполнился.

Переопустошился (или как это будет по русски?).
defunct
Все-таки переполнился.
Возможность зануления адреса возврата есть только на этой строке:

USART0_TX_Tail = temp_tail;


После линковки создается отчет по расходу памяти. Посмотрите сколько памяти данных у Вас занято?

(все что остается - отдается под стек, я не позволяю себе оставлять под стек меньше 256 байт).
ProfessorBraz
Вот это скорость ответов на форуме! Супер!

К теме
Код
239:              USART0_Enable_Int_Status = 1;
+000002D1:   E081        LDI     R24,0x01         Load immediate
+000002D2:   93800167    STS     0x0167,R24       Store direct to data space
+000002D4:   91FF        POP     R31              Pop register from stack
+000002D5:   91EF        POP     R30              Pop register from stack
+000002D6:   919F        POP     R25              Pop register from stack
+000002D7:   918F        POP     R24              Pop register from stack
+000002D8:   900F        POP     R0               Pop register from stack
+000002D9:   BE0F        OUT     0x3F,R0          Out to I/O location
+000002DA:   900F        POP     R0               Pop register from stack
+000002DB:   901F        POP     R1               Pop register from stack
+000002DC:   9518        RETI                     Interrupt return


Занятость:
Data: 383 bytes (37.4% Full)

Чем может переполниться стек, если программа только получает и отсылает по 5-7 Байт? help.gif
Палыч
Цитата(ProfessorBraz @ Apr 17 2008, 15:09) *
Чем может переполниться стек, если программа только получает и отсылает по 5-7 Байт? help.gif
Так Вы в Студии и проконтролируйте стек: состояние стека и содержимое его когда вошли в прерывание, и когда выходите (перед RTI). Должно быть одним и тем же.
ProfessorBraz
Цитата(Палыч @ Apr 17 2008, 16:22) *
Так Вы в Студии и проконтролируйте стек: состояние стека и содержимое его когда вошли в прерывание, и когда выходите (перед RTI). Должно быть одним и тем же.


указатель стека при входе и выходе не отличаются, короче. сколько запаковывается, столько же и распаковывается. Содержания стека я в студии не нашел. Может подскажешь, палычь, где оно в студии зарыто? 07.gif
galjoen
Цитата(Палыч @ Apr 17 2008, 16:22) *
Так Вы в Студии и проконтролируйте стек: состояние стека и содержимое его когда вошли в прерывание, и когда выходите (перед RTI). Должно быть одним и тем же.

+1
И регистры должны то-же значение иметь, и адрес возврата в стеке д.б.
Вы в прерывание как входите? М.б. вы просто адрес возврата в стек не кладёте? Надо при отладке call/rcall команду на таблицу прерываний делать.
ProfessorBraz
Цитата(galjoen @ Apr 17 2008, 16:35) *
+1
И регистры должны то-же значение иметь, и адрес возврата в стеке д.б.
Вы в прерывание как входите? М.б. вы просто адрес возврата в стек не кладёте? Надо при отладке call/rcall команду на таблицу прерываний делать.

Опа?! А вот с этого места по подробнее. Я всю жизнь думал, что при вызове прерывания адрес возврата сохраняется автоматически в стек. Если это не так, то как это делается и в каком месте. Я же не знаю в какой момент прерывание произойдет. Где этот код распологать? crying.gif
galjoen
Цитата(ProfessorBraz @ Apr 17 2008, 16:45) *
Опа?! А вот с этого места по подробнее. Я всю жизнь думал, что при вызове прерывания адрес возврата сохраняется автоматически в стек.

Правильно думали.
Цитата(ProfessorBraz @ Apr 17 2008, 16:45) *
Если это не так, то как это делается и в каком месте. Я же не знаю в какой момент прерывание произойдет. Где этот код распологать? crying.gif

Это только для отладки. А как у вас прерывание от USART при отладке вызывается?

А чтоб стек проконтролировать - надо ОЗУ начиная с адреса указателя стека посмотреть.
Палыч
Цитата(ProfessorBraz @ Apr 17 2008, 15:09) *
Занятость:
Data: 383 bytes (37.4% Full)
Чем может переполниться стек, если программа только получает и отсылает по 5-7 Байт? help.gif
Действительно, обработчик прерывания, фрагмент кода которого Вы привели использует 9 байт стека. Но стек также использует и основная программа: для адресов возврата из вызываемых подпрограмм, для размещения локальных переменных и массивов, передачи параметров процедурам и функциям... Разные трансляторы используют стек по-разному. Я плохо знаком с WinAVR, и не могу сказать - что со стеком делает он... Но, во всех трансляторах (ИМХО) самые прожорливые до памяти функции - printf, scanf и им подобные. Используете ли Вы подобные процедуры? Есть ли в Вашей программе большие локальные массивы?
Цитата(ProfessorBraz @ Apr 17 2008, 15:32) *
Содержания стека я в студии не нашел. Может подскажешь, палычь, где оно в студии зарыто?
Стек распалагается в памяти - для просмотра можно использовать окно Memory.
Цитата(ProfessorBraz @ Apr 17 2008, 15:45) *
Я же не знаю в какой момент прерывание произойдет. Где этот код распологать?
Делать искуственный вызов процедуры прерывания из программы не надо - достаточно "пошевелить" флаги - само произайдёт. Кстати, Вы ведь умудрились увидеть как-то вот это
Цитата(ProfessorBraz @ Apr 17 2008, 14:31) *
При просмотре в Студии в режиме ассемблега, видно что в переходе на прерывание все пакуется в стек, потом также аккуратно распаковывается, и возвращается по команде RTI, но почемуто в старт?
Как? Ну, так сделайте это же ещё раз с контролем стека.
P.S. Последняю цитата, может быть, говорит только о том, что Вы увидели в окне команды push/pop/reti? Тогда, как Вы определили, что именно по reti этого обработчика программа попала на нулевой адрес?
ProfessorBraz
Переход осуществляется на адресс указанный в стеке. Странно только,что команда RTI ситает из стека 2 байта (0х20 0хЕ8) а переходит на 0хЕ8. Но такого адресса 0х20Е8 или 0хЕ820 все равно нет. В стеке все нормально, до переполнения ему еще очень долеко, там всего 38 байт. wacko.gif
Палыч
Цитата(ProfessorBraz @ Apr 18 2008, 09:58) *
Странно только,что команда RTI ситает из стека 2 байта (0х20 0хЕ8) а переходит на 0хЕ8.
Возможно, Вы не учитываете то, что Stack Pointer указывает на свободную ячейку: содержимое стека - выше. Т.е., если возврат на 0х00Е8, то в ячейке +1 должен быть 00, в ячейке +2 должно быть Е8.
Отчего всё же Вы решили, что на адрес 0 попадаете по reti из этого обработчика?
ProfessorBraz
Цитата(Палыч @ Apr 18 2008, 12:03) *
Отчего всё же Вы решили, что на адрес 0 попадаете по reti из этого обработчика?

потому-что после reti программа переходит вот сюда
Код
+000000E4:   E081        LDI     R24,0x01         Load immediate
+000000E5:   93800184    STS     0x0184,R24       Store direct to data space
+000000E7:   CFFF        RJMP    PC-0x0000        Relative jump


теперь это Е7.
Палыч
Цитата(ProfessorBraz @ Apr 18 2008, 11:20) *
потому-что после reti программа переходит вот сюда
Это не переход на адрес 0. Очень похоже на бесконечный цикл, в конце программы, в который попадают при выходе из main. Сама main у Вас как выглядит?
ProfessorBraz
Цитата(Палыч @ Apr 18 2008, 12:36) *
Это не переход на адрес 0. Очень похоже на бесконечный цикл, в конце программы, в который попадают при выходе из main. Сама main у Вас как выглядит?

вот так
Код
int main(void)
{
    //Init UART
    InitUSART0_Int();
    USART_Init_Function(&i16RcvByte, &vOnEvent, &vOnError);
    InitFD();
    InitSM();
    // Interrupt erlauben
    sei();
    Global.bShortTaskEnable = true;    

    while(1){;}        
}
Палыч
Тот rjmp по адресу E7 - это скорее всего while(1){;}
Вас, наверное, смутили нули при jmp'е? Так обратите внимание, что они входят в выражение "РС-0х000", что означает "этот адрес", т.е. команда перехода на самою себя.
ProfessorBraz
Цитата(Палыч @ Apr 18 2008, 12:58) *
Тот rjmp по адресу E7 - это скорее всего while(1){;}
Вас, наверное, смутили нули при jmp'е? Так обратите внимание, что они входят в выражение "РС-0х000", что означает "этот адрес", т.е. команда перехода на самою себя.


а после этого он переходит вот сюда
Код
+0000001A:   940C0047    JMP     0x00000047       Jump
+0000001C:   940C0047    JMP     0x00000047       Jump

а от туда уже
Код
+00000047:   940C0000    JMP     0x00000000       Jump
Палыч
Ну, Вы, блин, даёте! Это не RJMP PC-0x0000 переходит на адрес 1A!
Адрес 1А - адрес вектора "USART, Tx Complete". У Вас разрешено прерывание по этому событию, но, обработчика прерывания, скорее всего, - нет. Вот программа и выходит на вектор, куда во избежании всяких неприятностей по-умолчанию занесены переходы, которые приводят на адрес 0.
ProfessorBraz
у меня только два прерывания и оба оброботчика присутствуют
Код
#if defined (__AVR_ATmega16__) || \
        defined (__AVR_ATmega32__)                                        
            #define ATMEGA_USART                                        
            #define USART0_RECEIVE_INTERRUPT    USART_RXC_vect            
            #define USART0_TRANSMIT_INTERRUPT    USART_UDRE_vect            
            #define USART0_STATUS    UCSRA                                    #define USART0_CONTROL    UCSRB                        
            #define USART0_DATA        UDR                        
            #define USART0_UDRIE    UDRIE                            
            #define USART0_UBRRH    UBRRH                            
            #define USART0_UBRRL    UBRRL


Палыч! Вы супер! a14.gif
Найдено. Проблема была в отсутствующем обработчике прерывания.
Код
ISR(USART0_TX_COMPLETE_INT)
{
}

Не смотря на то, что я это прерывание не разрешал, впрочем и не запрещал, возможно оно разрешилось автоматически вместе с Тх интераптом.

Вообщем проблема решена! Огромное всем спасибо! beer.gif
До следующих проблем!
Палыч
Если бы Вы в своём вопросе привели бы всю информацию, что "нарыли", то первым же ответным постом получили бы нормальный ответ. Никто бы не гадал на кофейной гуще, и проблема была бы решена ещё вчера.... Примите это к сведению, если будете задавать вопрос.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.