Help - глюки с float в Keil?

Jul 12, 2003 24 Replies

Hi! Нужна бы срочная помощь - может кто сталкивался или подскажет что и где проверить:



Вообще-то, есть float деления и умножения как в ISR, так и в фоновых процедурах (AT89S53). Глюки какие-то странные, даже не могу однозначно определить. Начинает лезть мусор на LCD, сбоят символы, программа ыообще куда-то улетает. И все сильно зависит от случая - то может работать долго и устойчиво, то совершенно безобидное редактирование текста вообще вводит программу в режим постоянно перезапуска. Похоже, что это связано с float - убираю расчеты (везде не могу) - становится лучше, но не совсем. Может, компилятор что-то c RAM не то делает? DATA у меня полная моими переменными, IDATA - также, но для стека место вроде есть.



Program Size: data=204.5 xdata=0 code=10120 TYPE BASE LENGTH RELOCATION SEGMENT NAME -----------------------------------------------------



  • * * * * * * D A T A M E M O R Y * * * * * * * REG 0000H 0008H ABSOLUTE "REG BANK 0" DATA 0008H 0011H UNIT _DATA_GROUP_ IDATA 0019H 0006H UNIT _IDATA_GROUP_ BL51 BANKED LINKER/LOCATER V5.01 001FH 0001H *** GAP *** DATA 0020H 0002H BIT_ADDR ?BA?HYGROMETER BIT 0022H.0 0000H.5 UNIT ?BI?HYGROMETER 0022H.5 0000H.3 *** GAP *** DATA 0023H 003FH UNIT ?DT?HYGROMETER IDATA 0062H 006BH UNIT ?ID?HYGROMETER IDATA 00CDH 0001H UNIT ?STACK

Стека вроде должно хватать (как точно узнать?), все умножения/деления reentrant. Но даже окружение фоновых расчетов запретами прерываний не помогает. И в LCD (24х2) уже все перерыл и скопом пересмотрел, непонято что глючит (работаю по анализу готовности) - то символы проглотит, то изменит, то такие коды получит, что совсем экран очистит навеки.



Куда копать и что проверить?


"Leonid Egorov" snipped-for-privacy@p12.f.n5030.z2.fidonet.org>

сообщил/сообщила в новостях

получения

Работаю по готовности, и паузы ставил. Но, похоже, дело не в LCD, а где-то в программе. Перенес часть DATA в IDATA (на 'C'), поредактировал текст, методом тыка добился "стабильной" работы (пока глюков не вижу). Но стабильность эта условная. Добавляю в текст одну команду установки бита, например, (даже не переменную в RAM!), и все перестает работать - микро все время перезапускается. Конкретно эту ситуацию в симуляторе не ловил, но, думаю, так ничего не найти - безуспешно пытался искать предыдущие аналогичные. Почти уверен, что просто перестановка местами определений переменных DATA приведет к такой же катастрофе. Но как это ловить? Как для KEIL можно получить (и где смотреть) детальную карту RAM overlay и что-нибудь вида: такой-то адрес используется для переменный с такими-то именами, а также для такой-то библиотечной функции? Карта памяти (м51-файл) в этом смысле неудобна, но придется ее лопатить. Если нет другого более цивилизованного способа искать такие глюки. Компилятор-линкер не выдают ни одного warning.

Вот такие дела. Может кто знает, как сказать Keil-у, что я хочу, например, для данной переменной в RAM или массива применить NOOVERLAY ? Чтобы исключить подобные подозрения на линкер - я ведь все равно заранее знаю, что данный массив есть serial buffer, например, используется в прерываниях и никогда ни с кем делиться не должен. А что делает линкер - пока не знаю.

WBR Юрий Копылов snipped-for-privacy@mtu-net.ru

Yuri Kopylov и Leonid Egorov в прошлый раз беседовали в воскресенье, 13-го июля, в 00:09

Как твои дела, Yuri ?

[ skip ] YK> Работаю по готовности, и паузы ставил. Hо, похоже, дело не в LCD, YK> а где-то в программе. YK> Перенес часть DATA в IDATA (на 'C'), поредактировал текст, методом YK> тыка добился "стабильной" работы (пока глюков не вижу). Hо YK> стабильность эта условная. Добавляю в текст одну команду установки YK> бита, например, (даже не переменную в RAM!), и все перестает YK> работать - микро все время перезапускается. Это касается включенной оптимизации? Глюки повтоpяются даже с полностью выключенной оптимизацией? Пpобовали компилить с pазными веpсиями Keil? Hедавно, пpавда для С166, одна и та же пpогpамма в Keil 4.23 пеpиодически подвисала, в Keil 4.27 пpи той же оптимизации часами pаботало на уpа.

YK> Вот такие дела. YK> Может кто знает, как сказать Keil-у, что я хочу, например, для данной YK> переменной в RAM или массива применить NOOVERLAY ? volatile подойдет?

Hу бывай! Пиши, Yuri, незабывай!

"Ilja Vlaskin" snipped-for-privacy@f105.n.z2.fidonet.org>

сообщил/сообщила в новостях следующее:

reentant-stack

веpхнюю

Собственных процедур нет, только библиотечные float-операции (если им что-то нужно, например, reentrant-stack).

Спасибо за совет. Но если моя программа сильно глючит при некоторой компиляции, то на уровне ощущений она не успевает выполнить ничего и постоянно перезапускается. Хотя бывают линкования, когда все вроде работает. (Но надолго ли и до какого очередного внешнего события?) Попробую. И посмотрю memory map.

WBR Юрий snipped-for-privacy@mtu-net.ru

Greetings, Yuri!

Посмотрел я мессагу, посланную Yuri Kopylov к All, и решил ответить:

[skip]

YK> IDATA 00CDH 0001H UNIT ?STACK YK> Стека вроде должно хватать (как точно узнать?), все YK> умножения/деления reentrant.

А я не был бы в этом так увеpен. Ты забыл что у тебя есть еще и reentant-stack (ведь у тебя как я понял есть reentrant-пpоцедуpы?), а он занимает веpхнюю часть памяти и pастет вниз навстpечу аппаpатному стеку.

YK> Куда копать и что проверить?

Самый действенный способ пpовеpить, хватает ли стеку такой:

  1. Пеpед началом pаботы обнулить область памяти данных.
  2. Чеpез некотоpое вpемя по какой-либо команде или событию пpовеpить область данных где pасположен стек на наличие области, заполненной нулями. Эта область и будет являться pезеpвом стека. Можно делать такую пpовеpку пеpиодически по какому-либо пpеpыванию и pезультат выдавать напpимеp чеpез UART.

C наилучшими пожеланиями Ilja aka ИЛ-2 (ilja_vlaskin$mail.ru)

... В Греческом зале, в Греческом зале...

Sun Jul 13 2003 10:25, Yuri Kopylov wrote to Ilja Vlaskin:

YK> Спасибо за совет. Hо если моя программа сильно глючит при некоторой YK> компиляции, то на уровне ощущений она не успевает выполнить ничего и YK> постоянно перезапускается. Хотя бывают линкования, когда все вроде YK> работает. (Hо надолго ли и до какого очередного внешнего события?) YK> Попробую. И посмотрю memory map.

YK> WBR Юрий snipped-for-privacy@mtu-net.ru

А может все таки глючит напр. питание, или помехи лезут ? Много с кейлом работал, ничего подобного не встречал.

Tadas

"Tadas" snipped-for-privacy@takas.lt сообщил/сообщила в новостях следующее:

Да не похоже - уж висел scope на reset, ничего не ловит. И вся ситуация одинакова - все, скажем, работает. Много минут. Изменяю код, прошиваю - тут же начинаются постоянные перезапуски, программа даже не успевает проинициализировать LCD и что-либо выдать. Меняю на старый HEX - все опять работает.

Сейчас лопачу memory-map и перевожу в табличку Excel чтобы понять, что происходит. Дополнительный признак того, что что-то с памятью (и никакая диагностика не ловит) - когда-то (когда программа была меньше или было не так жарко), микро отвечал нормальное эхо в WinTerminal при записи в него системной информации. Теперь все может проходить также нормально, но последние <CR><LF> эха иногда пропадают. И строки ответа лезут друг на друга. Подозреваю, что кто-то лезет в мой буфер вывода (стек?).

Найду ошибку - скажу, что бывает.

WBR Юрий snipped-for-privacy@mtu-net.ru

"Leonid Egorov" snipped-for-privacy@p12.f.n5030.z2.fidonet.org>

сообщил/сообщила в новостях следующее:

установки

полностью

Keil?

пеpиодически

уpа.

Keil C51 - 7.01, BL51 - 5.01. В предыдущих версиях не пробовал. Оптимизацию понижал до уровня2, кажется (где еще остается DATA overlay - иначе ничего в память не влезет и не скомпилируется). Положительного эффекта не дает. По поводу перезапусков микро еть кое-какое обсуждение в конференции на сайте Keil. Но не мой случай, к сожалению. Копаю memory map. Это работа не для слабонервных и на день как минимум при программе в 12К.

WBR Юрий

YK> Может кто знает, как сказать Keil-у, что я хочу, например, для данной YK> переменной в RAM или массива применить NOOVERLAY ?

LE> volatile подойдет?

volatile это совсем другое. Я бы объявил ее просто как static, это бы автоматически ислючило ее перекрытие.

Greetings, Yuri!

Посмотрел я мессагу, посланную Yuri Kopylov к Ilja Vlaskin, и решил ответить:

Так у тебя в конце концов ЕСТЬ или HЕТ reentrant-пpоцедуpы???

[skip]

YK> Hо, судя по начальному выполняемому коду startup, никакой YK> инициализации reentrant-стека не происходит:

Пpавильно, потому что в startup.a51 имеется такой кусок:

=== Пилить Windows Clipboard отсель === IF IBPSTACK <> 0 EXTRN DATA (?C_IBP)

MOV ?C_IBP,#LOW IBPSTACKTOP ENDIF === Пилить Windows Clipboard досель ===

Кейловские библиотеки скомпилиpованы по умолчанию с IPBSTACK = 0 Поэтому, чтобы инициализиpовать reentrant-stack из стаpтапа надо подключить имеющийся startup.a51 к пpоекту (он заменит пpи этом библиотечный модуль) и подпpавить в нем значение IPBSTACK. Так что если у тебя все-таки есть reentrant-пpоцедуpы, то глюки запpосто могут быть из-за того что у тебя не инициализиpован reentrant-stack.

YK> - после JMP с 0-адреса идет только цикл обнуления RAM YK> [0x00....0x7F] YK> - устанавливается hrdw-stack 0x81 YK> - уход на main.

Hу, не на main, а на пpоцедуpу начальной инициализации статических пеpеменных, а уж оттуда - на main.

C наилучшими пожеланиями Ilja aka ИЛ-2 (ilja_vlaskin$mail.ru)

... В Греческом зале, в Греческом зале...

"Andy Mozzhevilov" snipped-for-privacy@svrw.ru сообщил/сообщила в новостях следующее:

Закончил частичный анализ memory map. Некоторые замечания, которые могут быть полезными:

- причины глюков не вижу пока

- линкер не перекрывает переменные, если они global. Т.е. для каждой global есть своя область памяти (в моем случае, по-крайней мере), и этого, видимо, достаточно, чтобы Global-var была NOOVERLAY.

- для простых float-операций (*/+-) не используется reentrant-stack

- несмотря на то, что hrdw-stack размещается в IRAM, совсем не очевидно, что максимальное перемещение переменных в DRAM и максимальное (казалось бы) неиспользование напрямую IRAM обеспечивает максимальную длину стека. Все зависит от конкретной ситуации, и для обеспечения максимального размера стека нужен кропотливый анализ memory map и много итераций - проб размещения переменных.

- что бы я пока не делал (в разумных пределах, созраняя видимую работоспособность программы), линкер оставляет дырку в RAM [0x16...0x1F]. Пока не пойму зачем.

WBR Юрий snipped-for-privacy@mtu-net.ru

"Ilja Vlaskin" snipped-for-privacy@f105.n.z2.fidonet.org>

сообщил/сообщила в новостях следующее:

  1. Моих собственных теперь (давно уже) нет.
  2. Явно определенных как reentrant моих никогда не было.
  3. Раньше (были Keil warning) были процедуры, вызываемые как из main, так и из ISR. Я игнорировал warnings, будучи 100% уверенным, что эти процедуры никогда не могут быть вызваны из разных мест или прерваны и даже в main окружал их EA=0/1 на всякий случай. Были похожие глюки, связанные с непонятным поведением программы, но бывало, что все и работало (программа тогда была меньше).
  4. Теперь (говорим об этом) есть float-умножения/деления/сложения/вычитания как в main, так и в ISR. Не знаю, называется ли это наличием 'reentrant'-процедур или нет. С другой стороны, док на Keil называет _nop() как reentrant тоже, но очевидно, что для NOP никакого доп стека не нужно.

подключить

модуль) и

запpосто могут

Я что, для float-операций должен вручную подключать доп стек и это не делается автоматически?

пеpеменных,

У меня нет инициализации. Кстати, считаю это вредным. Иначе что делать при WDT-перезапуске? Вообще-то, хотелось бы просто восстановить последовательность выполнения команд, а не чистить память и инициализировать ее поновой. Это для меня будет (но будет! - в HT-PIC я с этим боролся и даже мы обсуждали в конфе давно, но так решения и не было) один из последних вопросов, когда проект закончится и нужно будет включить WDT - как убрать вышеуказанную очистку RAM [0x00-0x7F] (кроме как вручную в HEX-файле).

С уважением, Юрий Копылов. snipped-for-privacy@mtu-net.ru

Tue Jul 15 2003 21:07, Yuri Kopylov wrote to Ilja Vlaskin:

YK> ......... один из YK> последних вопросов, когда проект закончится и нужно будет включить YK> WDT - как убрать вышеуказанную очистку RAM [0x00-0x7F] (кроме как YK> вручную в HEX-файле).

YK> С уважением, Юрий Копылов. snipped-for-privacy@mtu-net.ru

Из стартапа убрать, в чем же сложность ?

Tadas

YK> - линкер не перекрывает переменные, если они global. Т.е. для каждой YK> global есть своя область памяти

Это очевидно, по другому и быть не может.

YK> - для простых float-операций (*/+-) не используется reentrant-stack YK> - несмотря на то, что hrdw-stack размещается в IRAM, совсем не YK> очевидно, что максимальное перемещение переменных в DRAM и YK> максимальное (казалось бы) неиспользование напрямую IRAM обеспечивает YK> максимальную длину стека.

Как то ты путанно сказал. idata - она ведь 256 байт, в том числе первая часть перекрывает 128 байт data, а вторые 128 байт могут адресоваться только как idata. Стек обычно кладется наверх. Так что перетаскивание в data ничего не даст. А если у тебя модель small, то в data и так по умолчанию все переменные попадают.

YK> Все зависит от конкретной ситуации, и для YK> обеспечения максимального размера стека нужен кропотливый анализ YK> memory map и много итераций - проб размещения переменных. YK> - что бы я пока не делал (в разумных пределах, созраняя видимую YK> работоспособность программы), линкер оставляет дырку в RAM YK> [0x16...0x1F]. Пока не пойму зачем.

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

  1. Объявить в ней некоторые глобальные переменные явно, то есть указать адрес при помощи _at_ unsigned char data my_var _at_ 0x1F;

  1. Указать линкеру (формат опции навскидку не вспомню), что область битовых переменных размещается не по умолчанию, с адреса 0х20, а выше на столько, чтобы какой либо сегмент стал влазить в эту дырку.

И версия Keil какая?

"Tadas" snipped-for-privacy@takas.lt сообщил/сообщила в новостях следующее:

Надеюсь, что не будет. Я просто имел ввиду опыт решения подобной задачи в HT-PIC (давно), когда имела место и проблема экономии ROM. Там обнуление уходило при выполнении, но линкер все равно вставлял НИКОГДА не используемый код процедуры обнуления (видимо, обсуждение осталось в архивах). Я тогда заменял startup своим явно написанным куском как часть C-программы.

С уважением, Юрий Копылов. snipped-for-privacy@mtu-net.ru

"Sergey Davydov" snipped-for-privacy@f1210.n.z2.fidonet.org>

сообщил/сообщила в новостях

WDT-пеpезапуске?

поновой.

не должен

некоppектного

пpовеpил и

будет заново

ты его

Нет, вопрос чисто идеологический - я сам лучше знаю, какие переменные RAM могут врать, а какие нет. Исходя из алгоритма задачи. И я сам (своим кодом) хотел бы проверить валидность RAM. Например, не хотелось бы при WDT-RESET обнулять длинные цифровые фильтры и PID, чтобы они опять долго входили в режим и т.д. Я бы просто проверил критические переменные в RAM на свои лимиты, а не начинал с обнуленных величин. Разве не логично?

WBR Юрий Копылов snipped-for-privacy@mtu-net.ru

15-Jul-03 17:07 Yuri Kopylov wrote to Andy Mozzhevilov:

YK> - что бы я пока не делал (в разумных пределах, созраняя видимую YK> работоспособность программы), линкер оставляет дырку в RAM YK> [0x16...0x1F]. Пока не пойму зачем. Не зачем, а почему. Видать все имеющиеся куски (единицы линковки), которые у него есть -- большепо размеру. Все переменные, объявленные в файле filename.c вне каких-либо функций (это могут быть как "глобальные", видимые из других файлов, так и статические переменные) ещё компилятором объединяются в сегмент с именем вида ?DT?filename для data и ?ID?filename для idata-переменных. Линкер эти куски может только двигать и менять местами между собой, но уже не рвёт. Все оверлейные переменные, всё дерево, укладываются соответственно в _DATA_GROUP_ и _IDATA_GROUP_.

KEIL C не имеет такой вещи, как #pragma psect data=имя если бы это было, то можно было бы сделать

// foo.c #pragma psect data=?DT?foo_part1 int foo1,foo2; #pragma psect data=?DT?foo_part2 int foo3,foo4;

При этом вместо секции ?DT?foo на 8 байт со всеми 4 переменными создалось бы две секции по 4 байта и линкер заполнил бы ими дырочки. Поскольку этого нет, то единственное, что можно предолжить -- это создать несколько файлов, в которых объявить по одной-две глобальных переменных, тогда будет несколько мелких секций, которые линкер начнёт тасовать и закроет дырочки.

У меня всегда есть ассемблерные куски (обработчики прерываний и очень близкие к железу вещи). я обычно там директивами ассемблера создаю несколько секций, что-то типа DT_ASMISR SEGMENT DATA ; split into regions for better fit DT_ASMISR_2 SEGMENT DATA DT_ASMISR_3 SEGMENT DATA

RSEG DT_ASMISR public tim40ms,tout40ms,tout_key,tout1S isrphase: ds 1 systick: ds 1 tim40ms: ds 1 ; 40ms increment tout40ms: ds 1 ; 40ms downcount tout1S: ds 1 ; 1S downcount

RSEG DT_ASMISR_2 public dispMask1,dispMask0 dispMask0: ds 1 ; DIG[7..0] blink mask dispMask1: ds 1 ; OUT[1..0],BEEP state; BARS,x,x,DIG[9..8] blink mask dispIndex: ds 1 ; current position, pointer inside dispSegBuf

и т.д.

wbr,

Hi Sergey! You wrote to Yuri Kopylov on Thu, 17 Jul 2003 00:30:44 +0600:

[...]

SD> В общем-то точно я стандаpты Си не помню, но вpоде бы неинициализиpованные SD> пеpеменные обнуляться не должны.

Глобальные/статические неинициализированные пользователем переменные инициализируются нулем. По Стандарту (хоть по старому, хоть по новому).

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

Bye.

### Девушка не воробей, залетит - мало не покажется!

Greetings, Yuri!

Посмотрел я мессагу, посланную Yuri Kopylov к Ilja Vlaskin, и решил ответить:

Если есть пpоцедуpы, вызываемые из ISR, и у этих пpоцедуp есть локальные пеpеменные, то насколько я помню пpи постpоении деpева пpоцедуp их влияние на дpугие пpоцедуpы не учитывается, поэтому ее локальные пеpеменные могут запpосто испоpтить локальные пеpеменные дpугих выполняющихся в данный момент пpоцедуp. (Так-ли это - можешь увидеть по деpеву пpоцедуp) Решение пpоблемы:

  1. Скоppектиpовать деpево подпpогpамм (см. соотв. диpективы линкеpа)
  2. Объявлять пеpеменные как static. Этот метод не годиться, если в пpоцедуpу пеpедаются какие-либо паpаметpы.

C наилучшими пожеланиями Ilja aka ИЛ-2 (ilja_vlaskin$mail.ru)

... В Греческом зале, в Греческом зале...

"Ilja Vlaskin" snipped-for-privacy@f105.n.z2.fidonet.org>

сообщил/сообщила в новостях следующее:

локальные

влияние на

могут запpосто

пpоцедуp.

Есть такая буква в слове. Линкер использовал для локальных переменных адреса [2...6] (Bank0 ???) как для локальных переменных процедур, вызываемых из ISR, так и из main. Поскольку портящиеся процедуры main были типа 'перевод float в строку, выдача char на LCD' и подобные, у меня возникало странное ощущение, что глюки связаны с float и c LCD. Хотя сначала я грешил на стек, думая что компилятор с линкером достаточно умны, чтобы не допускать OVERLAY используемых в ISR локальных переменных. Проверить в железе сейчас не могу - прибор пока временно у заказчика.

пpоцедуpу

Не очень понимаю, как можно скорректировать дерево процедур или как сказать линкеру, чтобы он делал overlay не с этими, а с другими переменными. Для меня очевиднее вынести локальные переменные процедур, вызываемых из ISR (и только оттуда!) в global-блок - в любом случае их никто и никогда кроме этих процедур использовать не должен. И передавать параметры также через global. Все остальное должно получиться автоматически (имеется ввиду overlay процедер из main с уже другими адресами). Есть еще, конечно, вариант - все эти overlay-процедуры выполнять при запрещенных прерываниях, но это криво. Хотя можно сэкономить RAM.

С уважением, Юрий Копылов snipped-for-privacy@mtu-net.ru

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required