Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Глюки программирования mega128
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Who_are_you?
Программирую систему на ATmega128
и неважно на СИ или Паскале в WinAvr или МикроПаскале

Но возникает ситуация когда прошу, например,
подпрограмме вывести на LCD текст, а она вываливается (перезапускает main);
или не выполняются переходы при работе с прерываниями.

Я предполагал что это из-за стека, но нигде не видел в реальных программах даже обращений к стеку.
Мои эксперименты со стеком ничего не дали.
Как добиться логичности, чтобы переходы были такие, как написаны в программе, а не с глюками?
Не могут же разные компиляторы иметь похожие проблемы!
Непомнящий Евгений
Вы название темы правильно указывайте - "Глюки моей программы для мега128" sm.gif

Что значит "не видел в реальных программах даже обращений к стеку"? Как только в программе появляется функция, так сразу там есть обращение к стеку.

А по теме - отлаживайте. Если есть отладчик - после появления проблемы останавливайте выполнение и смотрите, где вы оказались и почему, какое состояние стека, глобальных данных. Дальше ставите бряки (в т.ч. на изменение данных) и выясняете проблемное место.

Если отладчика нет - делаете минимально работающую программу и постепенно добавляете в нее функционал. Когда появляются проблемы - тщательно изучаете добавленное последним...

Причину перезагрузки (сброс, вотчдог и т.п.) можно выяснить, в меге128 помнится есть соотв. регистр.
Who_are_you?

Непомнящий Евгений, спасибо за корректировку выражений.

Почему-то не могу настроить WinAvr совместно с AvrStudio

Как поймать неправильный выход из подпрограмм?
По программе я после Break должен выйти из for,
а реально начинается перезагруз заново main.

Может есть для мега128 какой-то общий подход, в том числе и контроля стека?
Непомнящий Евгений
Цитата(Who_are_you? @ Aug 9 2017, 18:35) *
Может есть для мега128 какой-то общий подход, в том числе и контроля стека?


Заполните стек неким паттерном (0xdeadbeaf или на ваш вкус) и гляньте, что с ним сразу после перезагрузки. Дальше можно поставить бряк на изменение памяти вблизи низа стека - по идее в нормально режиме работы ваша программа туда доходить не должна.

Узнайте причину перезагрузки (см даташит, есть какой-то регистр с соотв. флагами). Если это вотчдог - отключите его, так проще выловить зависания ПО.

А так - получите минимальную рабочую программу и постепенно добавляйте кусочки.

Who_are_you?
вотчдог - отключен

программа большая, но была рабочая: LCD- работа с меню
Добавляю кусочками

Все работало пока не всунул работу с портом по прерыванию.
Прерывание настроил, но в некоторых случаях из глубины меню
нет выхода по программе, а реально начинается перезагруз заново main.
aiwa
Вначале функции main прочитайте регистр MCUSR: в нем побитовые источники перегрузки контроллера.

Очень странно, что контроллер ресетится: при программной ошибке это довольно маловероятное событие, скорее он должен просто зависнуть.
Ресет наводит на мысль перегрузки по аппаратной причине: собака, или просадка питания.
Непомнящий Евгений
Цитата(Who_are_you? @ Aug 9 2017, 19:47) *
Все работало пока не всунул работу с портом по прерыванию.
Прерывание настроил, но в некоторых случаях из глубины меню
нет выхода по программе, а реально начинается перезагруз заново main.


Вот сюда и копайте. Нет ли "гонки" между основной программой и прерыванием (volatile, запрет прерываний при работе с разделяемыми данными), нет ли вызова каких-то "тяжелых" функций из прерывания (который кушают много стека) и т.п.

Засеките размер используемого стека до и после прерывания, вставьте проверку - если стека осталось мало - повиснуть, выдав наружу сигнал об этом
aiwa
Проверьте на всякий случай фьюзы.
Не установлен ли фьюз совместимости с 103.
Who_are_you?
Я в чем не прав?

Код
#define   BUFFER_SIZE  255 //
unsigned char RxBuf [BUFFER_SIZE];  //

// void LCD_WriteText (char font, char * text)  

void PRFMenu (void)  //
{

char *buffer="0";
char cchh;
unsigned char rank[3] = {0,0,0};

cchh = (char)RxBuf[7];                          LCD_WriteText (8,&cchh); // 1
            
itoa (RxBuf[3],buffer,10);                       LCD_WriteText (8,buffer);  // 2
itoa (rank[2], buffer, 10);                       LCD_WriteText (8,buffer);  // 3
}


объявление указателя buffer на строку из 2 байтов
// 1 - в RxBuf[7] - символ
а во 2 и 3 случае в buffer запихивается байт или больше
или нужно присвоение через cchh = RxBuf[3],
чтобы стек не вводить в казус?
Непомнящий Евгений
Цитата(Who_are_you? @ Aug 11 2017, 12:29) *
Я в чем не прав?


ну вообще говоря при чем тут стек?
Код
char *buffer="0"; // это указатель на константу в памяти. Си дает так сделать? Может и дает, но менять ее нельзя. Для avr это по факту будет 2 байта в ОЗУ
itoa (RxBuf[3],buffer,10); // вы меняете константу  :maniac: Более того, если RxBuf[3] скажем 123, то вы меняете 4 байта (1,2,3,\0), т.е.  расстреливаете 2 байта ОЗУ после этой константы


Лучше как-то так
Код
char buffer[4];
itoa (RxBuf[3],buffer,10);


Who_are_you?
Цитата
ну вообще говоря при чем тут стек?

объявление переменной в подпрограмме занимает место в стеке
aiwa
Код
cchh = (char)RxBuf[7];                          LCD_WriteText (8,&cchh); // 1


Этот код тоже неаккуратный и он рабочий лишь потому, что в результате построения фрейма стека по соседству с cchh счастливым образом оказался завершающий строку ноль.
Who_are_you?
Почему в 1) случае выводится не всегда указанный текст,
а во 2) случае все четко

// void Text_Menu_String (char font, unsigned char x, unsigned char y, char * text) //
1)
Код:
Text_Menu_String (8,20,1, "Error_RS422: "); //

2)
Код:
char ER [] = "Error_RS422: ")
Text_Menu_String (8,20,1, ER); //

Разрешены прерывания только по UART ну и sei();
aiwa
Зависит от компилятора, но обычно для первого случая он генерирует такую же переменную, как и во втором случае:
Код
char _сгенерируемая_компилятором_метка_ [] = "Error_RS422: ";
Text_Menu_String (8,20,1, _сгенерируемая_компилятором_метка_);

только вот складирует эти переменные в самостоятельно определенном сегменте памяти.
Скорее всего именно эта память и портится.
KRS
Цитата(Who_are_you? @ Aug 15 2017, 12:40) *
Почему в 1) случае выводится не всегда указанный текст,
а во 2) случае все четко

потому что у avr классическая гарвардская архитектура (и флеш отмаплен только на адресное пространство команд, а озу только на данные) и константы из флеша загружаются специальными командами
во 2 случае данные из флеша копируются в переменную размещенную в ОЗУ.
А в 1, размещаются в стеке

В любом случае происходит лишнее копирование данных!
Поэтому для AVR функции которые принимают аргумент в виде константной строки используют специальный тип, что бы строка оставалась во флеше...
aiwa
Цитата(KRS @ Aug 15 2017, 18:04) *
во 2 случае данные из флеша копируются в переменную размещенную в ОЗУ.
А в 1, размещаются в стеке

Зависит от компилятора, но сейчас они не размещают строки в стеке.
При соответствующих установках компилятор сгенерирует полностью идентичный код для обоих случаев, скормив функции в 1 первом случае адрес ER.
Непомнящий Евгений
Цитата(aiwa @ Aug 15 2017, 21:55) *
При соответствующих установках компилятор сгенерирует полностью идентичный код для обоих случаев, скормив функции в 1 первом случае адрес ER.


А как он это сделает, если функция получает неконстантный буфер, т.е. может его модицифировать. В этом случае копирование во временный буфер не может быть соптимизировано...
Who_are_you?
Похоже WinAVR в 1-ом случае и загоняет в стек - отсюда и глюки.

Ещё два вопроса возникло:
WinAVR-20100110
Как стал объем
Program: 50.0% Full,
То *.hex - файл не шьется
делаешь 49.9 - все норм
WinAVR- вроде как свободна для распространения?

А стал отлаживать обмен данными по порту по прерыванию и непонятка:
командный кадр приходит (вижу при передачи в комп), но
на LCD видно не первый, а второй кадр
(просто цикл for(); и в нем вывод)
aiwa
Цитата(Непомнящий Евгений @ Aug 16 2017, 10:01) *
А как он это сделает, если функция получает неконстантный буфер, т.е. может его модицифировать. В этом случае копирование во временный буфер не может быть соптимизировано...

Да, виноват недосмотрел. Привык в последнее время, что все входящие буфера для вывода объявлены как 'const char*'.




Цитата(Who_are_you? @ Aug 16 2017, 15:16) *
Как стал объем
Program: 50.0% Full,
То *.hex - файл не шьется
делаешь 49.9 - все норм
WinAVR- вроде как свободна для распространения?


Наверное это связано с моделью памяти.
128-я регистрами может адресовать только 50% памяти - поэтому, пространство программ делится на две половины, выбор доступа к каждой из который осуществляется с помощью соответствующего бита в управляющем регистре.
Для маленьких моделей компилятор строит программу при условии что она будет располагаться в нижних 50% памяти.
Who_are_you?
И как обойти это или в WinAVR не возможно?

В конце концов не может же 50% висеть в воздухе!
aiwa
Цитата(Who_are_you? @ Aug 17 2017, 11:50) *
И как обойти это или в WinAVR не возможно?

В конце концов не может же 50% висеть в воздухе!


бит RAMPZ0 регистра RAMPZ отвечает за выбор банка при адресации команд ELPM/SPM.
Я не знаю как в WinAVR, но в общем это обходится выбором модели памяти (huge) при компиляции.
Тогда компилятор начинает использовать ELPM вместо LMP и отслеживает манипуляции с RAMPZ0.
Who_are_you?
Из Даташит:

Внутрисистемно программируемая флэш-память программ ATmega128 содержит 128 кбайт
внутренней внутрисистемно перепрограммируемой флэш-памяти для хранения программы.
Поскольку все AVR-инструкции являются 16 или 32-разр., то флэш-память организована как 64
кбайт х 16. Для программной защиты флэш-память программ разделена на два сектора: сектор
программы начальной загрузки и сектор прикладной программы.

Регистр RAMPZ обычно используется для указания той страницы ОЗУ размером 64 кбайт, к
которой выполняется доступ через Z-указатель. Т.к. ATmega128 не поддерживает память на
статическом ОЗУ размером свыше 64 кбайт, то данный регистр используется только для выбора
страницы памяти программ, доступ к которой осуществляется с помощью инструкций ELPM/SPM.
Различные установки бита RAMPZ0 имеют следующий результат:
RAMPZ0 =0:
Инструкции ELPM/SPM осуществляют доступ к памяти программ в диапазоне адресов
$0000 - $7FFF (младшие 64 кбайт)
RAMPZ0 =1:
Инструкции ELPM/SPM выполняют доступ к памяти программ в диапазоне адресов
$8000 - $FFFF (старшие 64 кбайт)
Обратите внимание, что действие инструкции LPM не зависит от установки RAMPZ.


Получается программно нужно как-то расширять возможности записи программ больше 64к
или все приехали: на данном микроконтроллере дальше не уедешь?
aiwa
Цитата(Who_are_you? @ Aug 17 2017, 16:12) *
Получается программно нужно как-то расширять возможности записи программ больше 64к
или все приехали: на данном микроконтроллере дальше не уедешь?

Для переменных есть модификаторы типа памяти, наподобие __farflash, __hugeflash и т.д.
При использовании библиотек - соответствующую модель памяти.






aiwa
Пример использования
Код
char ER [] = "Error_RS422: ";

#pragma location = 0x000100
__flash char ER_FLASH [] = "Error_RS422: ";

#pragma location = 0x010100
__hugeflash char ER_HUGE [] = "Error_RS422: ";

void main(void)
{

for(int i=0;i<10;i++)
  ER[i]=ER_HUGE[i];
for(int i=0;i<10;i++)
  ER[i]=ER_FLASH[i];
  
}

И работа компилятора
CODE

//копируем из верхней половины, здесь трехбайтный адрес в старшем байте которого принимается во внимание только младший бит, который имеет посадочное место RAMPZ0.

// 16 ER[i]=ER_HUGE[i];
MOV R26, R25
LSL R26
SBC R26, R26
MOV R27, R26
LDI R30, LOW(ER_HUGE)
LDI R31, HIGH(ER_HUGE)
LDI R19, (ER_HUGE) >> 16
ADD R30, R24
ADC R31, R25
ADC R19, R26
OUT 0x3B, R19 !!!!!!!!! заносим в RAMPZ третий байт адреса для нижних адресов это 0x00, для верхних адресов - 0x01
ELPM R16, Z !!!!!!!!! доступ к памяти программ через "длинный" вариант - ELP, т.е. через [RAMPZ0]:Z
MOVW R31:R30, R25:R24
SUBI R30, LOW((-(ER) & 0xFFFF))
SBCI R31, (-(ER) & 0xFFFF) >> 8
ST Z, R16

копируем из нижней половины. здесь двухбайтный адрес.
// 16 ER[i]=ER_HUGE[i];
MOV R26, R25
LSL R26
SBC R26, R26
MOV R27, R26
LDI R30, LOW(ER_HUGE)
LDI R31, HIGH(ER_HUGE)
LDI R19, (ER_HUGE) >> 16
ADD R30, R24
ADC R31, R25
ADC R19, R26
OUT 0x3B, R19
ELPM R16, Z !!!!!!!!! доступ к памяти программ через "короткий" вариант - LPМ, т.е. через Z
MOVW R31:R30, R25:R24
SUBI R30, LOW((-(ER) & 0xFFFF))
SBCI R31, (-(ER) & 0xFFFF) >> 8
ST Z, R16



demiurg_spb
Проблема в чём-то другом.
У вас ведь программа не состоит только из данных во флеше, а есть ещё и код программ.
avr-gcc (см скрипт линкера и map-файл) обычно размещает секцию с данными перед секцией кода.
Поэтому проблемы с заполнением памяти на 49% и 51% не следуют из вышеназванных предположений.

А на будущее рекомендую изучить файлик pgmspace.h
Цитата
a = pgm_read_byte_far(GET_FAR_ADDRESS(v));


Также есть смысл использовать более свежий тулчейн хотя бы avr-gcc-4.9.2 т.к. там появилась поддержка ключевого слова __flash (на подобии IAR).

https://sourceforge.net/projects/mobileches...%20%28Win32%29/
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.