Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Страшные глюки с Philips 80C32
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры
Shedon
Есть сабжевый контроллер, есть прога на си, код хранится во внешней флэш, на 64кб, есть графический дисплей с контроллером SED1335, стал замечать следующею зависимость: чем больше программа по объёму тем больше становится глюков, сейчас прога весит без оптимизации 56889bytes of code. глюки заключаются в следующем перестаёт выводить графику на экран()рисует какие-то линии от болды), и зависает на этом, причём скол-во глюков зависит неким образом от оптимизации. Больше всех глючат функции обращения к контроллеру дисплея, обработка прерывания от таймера и функции си типа sprintf, vsprintf
. Вот ниже привожу пример как у меня построена работа с дисплеем, эта функция рисует точку в один пихел.

Код
#define BASE_ADDR          0x5000
#define DISP_W_D ((char volatile*) 0x018000)
#define DISP_W_C ((char volatile*) 0x018001)
#define DISP_R_D ((char volatile*) 0x018001)
#define DISP_R_C ((char volatile*) 0x018000)

__data unsigned char n_bit,n_bat,d_byt;
__data unsigned int adress;

//...
//...

void put_pixel(int tx, int ty)
{
   n_bat = tx/8;
   n_bit = tx-n_bat*8;
   adress = BASE_ADDR+(ty*40+n_bat);

   *DISP_W_C=0x46;
   *DISP_W_D=adress;
   *DISP_W_D=adress>>8;
   *DISP_W_C=0x43;
   d_byt=*DISP_R_D;

   d_byt |= (0x80>>n_bit);

   *DISP_W_C=0x46;
   *DISP_W_D=adress;
   *DISP_W_D=adress>>8;
   *DISP_W_C=0x42;
   *DISP_W_D=d_byt;
}


Контроллер дисплея подключён как внешняя память, т.е. здаётся мне глюки происходят при обращение к внешней памяти. Как мне кажется я где-то ошибаюсь с настройками компилятора, да забыл написать, компилятор IAR8051 v6.11, эмулятор PICE51, ниже привожу коммандные файлы с настройками проекта может кто что подскажет, заранее спасибо.

Все файлы проекта компилируются со след. параметрами:
Код
--no_wrap_diagnostics --only_stdout
--core=pl
--code_model=n
--data_model=l
--nr_virtual_regs=8
--calling_convention=pr
--place_constants=data
--require_prototypes
--migration_preprocessor_extensions
-e
--enable_multibytes
-r
-lCN indic
--no_cse
--no_inline
--no_code_motion
--no_unroll
-IC:\PROGRA~1\IARSYS~1\EMBEDD~1.2EV\8051\inc\FileName.c


Илинкуются след. образом:
Код
-IC:\PROGRA~1\IARSYS~1\EMBEDD~1.2EV\8051\config
-D_EXTENDED_STACK_START=2000
-D_EXTENDED_STACK_END=23FF
-D_EXTENDED_STACK_SIZE=3FF
-D?DPS=86
-D_NR_OF_VIRTUAL_REGISTERS=8
-D?DPMASK=1
-D?CBANK=90
-D_CODEBANK_START=8000
-D_CODEBANK_END=10000
-D_IDATA_STACK_SIZE=0x90
-D_PDATA_STACK_SIZE=0x90
-D_XDATA_STACK_SIZE=0xFFF
-e_medium_read=_formatted_read
-l "KALIBR.MAP"
-xsm
-p80
-IC:\PROGRA~1\IARSYS~1\EMBEDD~1.2EV\8051\lib\clib\
-f "lnk51ew.xcl"
-FINTEL-EXTENDED
graf_r.R51
indic.R51
obr_klav.R51
pribor.R51
proverka.R51
sint_nch.R51
svitok.R51
upr_pkan.R51
ZNGENM10.R51
gui.R51
AT24C32.R51
ExchangePC.R51
C:\PROGRA~1\IARSYS~1\EMBEDD~1.2EV\8051\lib\clib\cl-pli-nlpd-1e.r51
-o KALIBR.hex


В итоге программа получается след. размеров:
55 565 bytes of CODE memory
70 bytes of DATA memory( + 11 absolute )
10 262 bytes of XDATA
149 bytes of IDATA
8 bits of BIT memory
bialix
я бы сказал, что у вас глючит или компилятор или переполняется стек

объем программы растет потому что добавляются функции? если да - то проверяйте стек
Shedon
Цитата(bialix @ Feb 8 2005, 17:52)
я бы сказал, что у вас глючит или компилятор или переполняется стек

объем программы растет потому что добавляются функции? если да - то проверяйте стек
*

Да программа растёт из-за функций
bialix
Вы писали:
Больше всех глючат функции обращения к контроллеру дисплея, обработка прерывания от таймера и функции си типа sprintf, vsprintf

Тогда это ОЧЕНЬ похоже на переполнение стека
тем более что функции sprintf, vsprintf очень прожорливы по отношению к стеку.

Начинайте анализировать дерево вызовов функций по листингу линкера, профилировать потребление стека своим отладчиком. Начинайте отключать какие-то функции. Затем вы дойдете до переписывания sprintf, vsprintf своими реализациями.
bialix
и просто мои 5 копеек: для 51х лучше юзать кейла. Мое сугубое личное мнение.
Shedon
Может просто размер стека увеличить ???

-------------------------------------------
PS
Открыл окно "Распределение памяти"", во вкладке CODE есть две странные строчки:
Код
Адрес                Размер              Имя                                           Значение
------------------------------------------------------------                  ---------------
//...
//...
C:FFFF                [1]                   _XDATA_END                                      [typless]
C:10000             [16711679]       _FAR__DATA_START, _CODE_BANK     *Address out of range*
C:FFFFFF            [4278255617]    _FAR_DATA_END, _CODE_END, _FAR_CODE_END                                                                                *Address out of range*
C:FFFF                                        ***End of adress space ***


Что такое находится по адресам C:10000 и C:FFFFFF
bialix
не знаю, я с яром для 51х не работал
Shedon
Цитата(bialix @ Feb 9 2005, 12:40)
не знаю, я с яром для 51х не работал
*

Да, похоже точно переполнение стека, сейчас просто перезапускается в опаределённый момент, первый раз с этим столкнулся, пока не вижу другого способа кромек как увеличить размер стека...
-Tумблер-
Цитата(Shedon @ Feb 8 2005, 15:54)
Есть сабжевый контроллер, есть прога на си, код хранится во внешней флэш, на 64кб, ....
.....
глюки
.....


Заочно трудно сказать - что там может быть. Возможно существует
и не одна причина. Можно посоветовать типа - "а что бы я сделал".

У 51-х есть известная проблема - "проблема ALE".
Решается вставкой резистора 430-560 ом в разрыв цепи ALE
процессор-регистр. Это я сделал бы автоматически, на уровне
инстинкта. Вне зависимости , улучшит это ситуацию или нет.

Далее, хочестя понять:
1. какова глубина вложения в стек - и хватит ли его.
Например, при старте программы прописать весь стек 0xFF.
А после некоторой работы вывести дамп стека на дисплей.
Сразу станет понятно, сколько заняли.

2. правильно ли читаются коды команд из внешней флэш -
нужно вставить проверку CRC16 вообще и пустить этот тест
циклически в частности. Для выяснения проблем этого эпизода. smile.gif

3. Тщательнее изучить диаграммы вывода на дисплей.
Может что-то "на грани". Заменить дисплей - может не повезло
с конкретным экземпляром.
Еще я бы нагрузил шину данных вывода (P0 если я не ошибаюсь)
резисторами 4K7 на питание. excl.gif

4. Временный откат назад - к простой и маленькой программе
которая работает исправно. Постепенное наращивание кода
до тех пор, пока не станет "плохо".
Или ловить "плохо" как льва в Африке. smile.gif
Miron
Согласен с высказываниями насчет стека.
Советую еще обратить внимание на построение прерываний
Если прерывания выполняются в разных банках и в них вызываются
функции скомпилированные под другой регистровый банк а СИ как
правило компилит все под 0 банк то возникают ошибки похожие на то,
что вы описываете.
Отловить такое лучше всего просматривая трассировку программы после
точки останова на ошибке.
IgorKossak
Позволю и себе высказаться.
Что касается стека, то поведение МК в этом случае очень симптоматично и причина, скорее всего, кроется именно в этом. Особенно когда я увидел ссылки в сообщениях на функции sprintf.
Но. Контроль стека предварительным заполнением его какой нибудь детерминированной величиной не на все 100% может дать нужный результат. Дело в том, что когда компилятор выделяет некое пространство в стеке под временные переменные, он просто меняет значение указателя стека (которое может указывать за пределы сегмента стека), но не обязательно что-то пишет в выделенное пространство. Поэтому в работе может сложиться впечатление, что стека ещё достаточно, но программа, тем не менее, падает, т. к. локальные переменные могут быть уже вне сегмента стека и затирают какие-нибудь глобальные переменные или случается прерывание, которое изменяя глобальные переменные на самом деле изменяет свой адрес возврата.
Поэтому, как ещё одна мера предосторожности, нужно расположить под стеком наименее ответственный сегмент данных, например сегмент со стрингами. Глюки в этом случае будет легче выявить и они не будут приводить к падению программы.
-Tумблер-
Цитата(IgorKossak @ Feb 12 2005, 15:49)
но не обязательно что-то пишет в выделенное пространство. Поэтому в работе может сложиться впечатление, что стека ещё достаточно, но программа, тем не менее, падает, т. к. локальные переменные могут быть уже вне сегмента стека

*



excl.gif Сушествует, конечно и второй метод (но я его считаю первым!!).
Это - определение экстремального значения указателя стека.
Очевидно, для x51 это тривиальный поиск максимума. (щас найдем):

#define SP_RESEARCH

#ifdef SP_RESEARCH
idata byte sp_pointer;
#endif

void main (void)
{
#ifdef SP_RESEARCH
/* search from this value */
sp_pointer = SP;
#endif

.
.
.

}

В какой-нибудь самой "глубокой" процедуре прерывания
(в таймерной например):
interrupt void T0_int (void)
{
TH0=wdTh;
TL0+=wdTl;
...
#ifdef SP_RESEARCH
/* max search !*/
if (sp_pointer < SP) sp_pointer=SP;
#endif
...
}

Далее по какому - нибудь событию (нажатие кнопки, таймер, "всегда")
выведем sp_pointer в COM-порт. Довольно быстро обнаружим
максимум. конечно, можно предложить вариант, когда это
не сработает - договоримся не делать таких проектов "И ФСЕ".

Замечу, что поскольку речь шла об IAR, это надо
сделать для ОБОИХ стеков. excl.gif
IAR любит использовать 2 стека. И оба желательно контролировать. excl.gif

Сочетание обоих методов позволяет решить проблему. blush.gif

Очевидно, это уже из серии дискуссии "кто и как тестирует.."
Совершенно очевидно, если бы автор программы контролировал
этот важнейший параметр по мере изготовления продукции,
те действовал "по шагам" ничего подобного бы не случилось.
А теперь нет гарантий, что этот проект вообще можно довести
до качественного результата.
smile.gif
-Tумблер-
Цитата(IgorKossak @ Feb 12 2005, 15:49)
..не на все 100% может дать нужный результат. ..
*


Хорошенько подумав, пришел к выводу, что все-таки
"так не может быть". Действительно, в случае создания
автоматических переменных в стеке сначала произойдет коррекция
SP. Если в этот момент произойдет прерывание, у стека
будет занято еще некоторое пространство. Которое, очевидно,
будет использовано раньше (чем пространство локальных переменных).
И что же ? После окончания прерывания, локальные переменные
будут использованы, и память в стеке также будет изменена.
Никаких "проплешин" использования стека не будет.
В этом случае поменяется лишь порядок искажения стекового
пространства. Однако, если после вывода дампа стека в ком-порт
мы обнаружим не искаженную область стекового "ковра памяти",
это одназначно будет указывать на отсутствие переполнения.
А вот если не искаженной области не будет совсем,
однозначного вывода сделать нельзя.
Но даже если и в "этом разе" переполнения нет, работать
так не рекомендуется.. любая последующая коррекция проекта может привести к самым разным результатам..
smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.