Перейти к содержанию
    

Страшные глюки с Philips 80C32

Есть сабжевый контроллер, есть прога на си, код хранится во внешней флэш, на 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я бы сказал, что у вас глючит или компилятор или переполняется стек

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

я бы сказал, что у вас глючит или компилятор или переполняется стек

 

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

Да программа растёт из-за функций

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы писали:

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

 

Тогда это ОЧЕНЬ похоже на переполнение стека

тем более что функции sprintf, vsprintf очень прожорливы по отношению к стеку.

 

Начинайте анализировать дерево вызовов функций по листингу линкера, профилировать потребление стека своим отладчиком. Начинайте отключать какие-то функции. Затем вы дойдете до переписывания sprintf, vsprintf своими реализациями.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может просто размер стека увеличить ???

 

-------------------------------------------

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не знаю, я с яром для 51х не работал

Да, похоже точно переполнение стека, сейчас просто перезапускается в опаределённый момент, первый раз с этим столкнулся, пока не вижу другого способа кромек как увеличить размер стека...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть сабжевый контроллер, есть прога на си, код хранится во внешней флэш, на 64кб, ....

.....

глюки

.....

 

Заочно трудно сказать - что там может быть. Возможно существует

и не одна причина. Можно посоветовать типа - "а что бы я сделал".

 

У 51-х есть известная проблема - "проблема ALE".

Решается вставкой резистора 430-560 ом в разрыв цепи ALE

процессор-регистр. Это я сделал бы автоматически, на уровне

инстинкта. Вне зависимости , улучшит это ситуацию или нет.

 

Далее, хочестя понять:

1. какова глубина вложения в стек - и хватит ли его.

Например, при старте программы прописать весь стек 0xFF.

А после некоторой работы вывести дамп стека на дисплей.

Сразу станет понятно, сколько заняли.

 

2. правильно ли читаются коды команд из внешней флэш -

нужно вставить проверку CRC16 вообще и пустить этот тест

циклически в частности. Для выяснения проблем этого эпизода. :)

 

3. Тщательнее изучить диаграммы вывода на дисплей.

Может что-то "на грани". Заменить дисплей - может не повезло

с конкретным экземпляром.

Еще я бы нагрузил шину данных вывода (P0 если я не ошибаюсь)

резисторами 4K7 на питание. :excl:

 

4. Временный откат назад - к простой и маленькой программе

которая работает исправно. Постепенное наращивание кода

до тех пор, пока не станет "плохо".

Или ловить "плохо" как льва в Африке. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость Miron

Согласен с высказываниями насчет стека.

Советую еще обратить внимание на построение прерываний

Если прерывания выполняются в разных банках и в них вызываются

функции скомпилированные под другой регистровый банк а СИ как

правило компилит все под 0 банк то возникают ошибки похожие на то,

что вы описываете.

Отловить такое лучше всего просматривая трассировку программы после

точки останова на ошибке.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Позволю и себе высказаться.

Что касается стека, то поведение МК в этом случае очень симптоматично и причина, скорее всего, кроется именно в этом. Особенно когда я увидел ссылки в сообщениях на функции sprintf.

Но. Контроль стека предварительным заполнением его какой нибудь детерминированной величиной не на все 100% может дать нужный результат. Дело в том, что когда компилятор выделяет некое пространство в стеке под временные переменные, он просто меняет значение указателя стека (которое может указывать за пределы сегмента стека), но не обязательно что-то пишет в выделенное пространство. Поэтому в работе может сложиться впечатление, что стека ещё достаточно, но программа, тем не менее, падает, т. к. локальные переменные могут быть уже вне сегмента стека и затирают какие-нибудь глобальные переменные или случается прерывание, которое изменяя глобальные переменные на самом деле изменяет свой адрес возврата.

Поэтому, как ещё одна мера предосторожности, нужно расположить под стеком наименее ответственный сегмент данных, например сегмент со стрингами. Глюки в этом случае будет легче выявить и они не будут приводить к падению программы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но не обязательно что-то пишет в выделенное пространство. Поэтому в работе может сложиться впечатление, что стека ещё достаточно, но программа, тем не менее, падает, т. к. локальные переменные могут быть уже вне сегмента стека

 

 

 

:excl: Сушествует, конечно и второй метод (но я его считаю первым!!).

Это - определение экстремального значения указателя стека.

Очевидно, для 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:

IAR любит использовать 2 стека. И оба желательно контролировать. :excl:

 

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

 

Очевидно, это уже из серии дискуссии "кто и как тестирует.."

Совершенно очевидно, если бы автор программы контролировал

этот важнейший параметр по мере изготовления продукции,

те действовал "по шагам" ничего подобного бы не случилось.

А теперь нет гарантий, что этот проект вообще можно довести

до качественного результата.

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

..не на все 100% может дать нужный результат. ..

 

Хорошенько подумав, пришел к выводу, что все-таки

"так не может быть". Действительно, в случае создания

автоматических переменных в стеке сначала произойдет коррекция

SP. Если в этот момент произойдет прерывание, у стека

будет занято еще некоторое пространство. Которое, очевидно,

будет использовано раньше (чем пространство локальных переменных).

И что же ? После окончания прерывания, локальные переменные

будут использованы, и память в стеке также будет изменена.

Никаких "проплешин" использования стека не будет.

В этом случае поменяется лишь порядок искажения стекового

пространства. Однако, если после вывода дампа стека в ком-порт

мы обнаружим не искаженную область стекового "ковра памяти",

это одназначно будет указывать на отсутствие переполнения.

А вот если не искаженной области не будет совсем,

однозначного вывода сделать нельзя.

Но даже если и в "этом разе" переполнения нет, работать

так не рекомендуется.. любая последующая коррекция проекта может привести к самым разным результатам..

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...