|
Пару вопросов по Си для MCS51, от начинающего... |
|
|
|
 |
Ответов
|
Dec 10 2008, 14:18
|
Знающий
   
Группа: Свой
Сообщений: 540
Регистрация: 16-08-07
Из: Владивосток
Пользователь №: 29 831

|
Цитата(AndreyS @ Dec 10 2008, 18:56)  Суть проблеммы В рабочем режиме иногда прошивка виснет. Выяснил, что зависает (зацикливается) она по причине того что локальные переменные процедуры кто-то запорол. Нашел в карте памяти что данные ячейки относятся еще к двум процедурам (причем там эти переменные тоже локальные). Одна из которых вызывается в прерывании. Как мне теперь заставить Keil убрать из перекрестных ссылок эти переменные (чтобы они лежали в разных адресах DATA)? Делать их глобальными внутри одного файла желания нет.
Пока я проверил только локальные переменные в области DATA, быть может такая петрушка есть еще с переменными в области XDATA. Почему Keil их так расположил? Ведь при компиляции он знает какие процедуры попадают в прерывание и по идее должен этим процедурам для локальных переменных выдилять свои адреса. Может нужно что-то указать??
Спасибо. Как я понял, у Вас есть функция которая вызывается из функции обработки прерывания? Если так, то это очень не гуд  . Для этого нужны очень веские основания. Только в том случае, если Вы эту функцию вызываете еще из другого места. Но эту ситуацию линкер возможно и не отслеживает и нужно в этой функции переменные объявить static, хотя это равносильно глобальной переменной. Да и тем более возможен повторный вход в функцию со всеми вытекающими. Этот вариант отметаем  Если же вызов только из прерывания, тогда лучше вобще обойтись без дополнительной функции, все стащить в одно место, в функцию-обработчик. Вы же наверняка пользуетесь using-ами, может быть линкер эти переменные через регистры протащит, будет маленькое счастье  . А нельзя вобще обойтись в прерывании без обработки, выставив соответствующий флажок и обработать в другом месте?
|
|
|
|
|
Dec 10 2008, 16:08
|

Местный
  
Группа: Участник
Сообщений: 235
Регистрация: 28-01-05
Из: Санкт-Петербург
Пользователь №: 2 276

|
Цитата(barabek @ Dec 10 2008, 17:18)  Как я понял, у Вас есть функция которая вызывается из функции обработки прерывания? Если так, то это очень не гуд  . Для этого нужны очень веские основания. Только в том случае, если Вы эту функцию вызываете еще из другого места. Но эту ситуацию линкер возможно и не отслеживает и нужно в этой функции переменные объявить static, хотя это равносильно глобальной переменной. Да и тем более возможен повторный вход в функцию со всеми вытекающими. Этот вариант отметаем  Если же вызов только из прерывания, тогда лучше вобще обойтись без дополнительной функции, все стащить в одно место, в функцию-обработчик. Вы же наверняка пользуетесь using-ами, может быть линкер эти переменные через регистры протащит, будет маленькое счастье  . А нельзя вобще обойтись в прерывании без обработки, выставив соответствующий флажок и обработать в другом месте? Огромное спасибо за содержательный ответ. В прерывании использую процедуру которая вызывается еще и по коду. Суть процедуры сформировать (подготовить запрос на SPI шину и поставить его в очередь). Т.е. по сути - это и флажок и короткий обработчик этого флажка. Да. Переосмыслил сейчас еще раз свой код и чую буду переделывать обработчик прерывания.  Да, тут я упустил из внимания возможность повторного вызова процедуры в неблагоприятный момент. Вы подняли мне веки  Правда это не отменяет объединения (отображения части переменных по одним и тем же адресам) локальных переменных двух разных процедур (я пока просто перебросил переменные в одной процедуре в XRAM и таким образом развязал эти процедуры). Буду переписывать обработчик.
Сообщение отредактировал AndreyS - Dec 10 2008, 16:21
--------------------
Удачи.
|
|
|
|
|
Dec 11 2008, 12:00
|

Местный
  
Группа: Участник
Сообщений: 235
Регистрация: 28-01-05
Из: Санкт-Петербург
Пользователь №: 2 276

|
Цитата(barabek @ Dec 11 2008, 03:31)  Если две функции не могут вызываться одновременно (случай с прерыванием) - то конечно же пусть они используют одни и те же адреса для локальных переменных. В этом и соль этих переменных в отличии от глобальных. Если посмотреть на листинг то почти в каждой функции для локальных переменных используются регистры. И это очень хорошо, это только плюс компилятору-линкеру. Ведь памяти очень немного  Добрый день. Спасибо всем за ответы. Все что Вы ранее высказывали, я прекрасно понимаю. Но тут вещь в следующем. Компилятор никогда не отображает локальные переменные на одни и теже адреса, если они пересекаются при вызове процедур (РАЗНЫХ ПРОЦЕДУР). Если переменные пересекаются (отображаются на одни и теже адреса) (РЕГИСТРЫ НАПРИМЕР), то компилятор при входе в такую процедуру сохраняет все эти регистры в стек. Если компилятор этого не делает - то это плохой компилятор. Анализирую код Keil'а он (Кейл) именно так и делает. Если я в перерывании (или процедуре) использую вызов процедуры, то в прерывании, перед ее выполнением, сохряняются все регистры и PSW в стек. Если я неиспользую каких либо регистров (ну компилятор в процессе компиляции ничего не задействовал), то на входе он ничего не сохраняет. Для Кейла я это проверял. Правда весь листинг виден только в самом проце, в выходных файлах этого нет. В данном примере происходит все именно так. Если у меня есть ряд процедур, которые могут вызваться из прерывания и у них есть локальные переменные, то компилятор не отражает на адреса этих переменных ничего из других процедур. В данном примере я заметил пересекающиеся области (две ячейки наложились. Две ячейки локальных переменных разных процедур). Причем ячеки входящих переменных (извиняюсь за корявость, но переменных через которые я передаю данные в процедуру). Есть функция Spi_RD в которую я передаю ряд параметров. Она вызывается в прерывании. Есть функция Filtrate_long в которую я передаю одно число и в нутри нее есть переменные счетчики. Так пересеклись две переменные из входящих переменных функции Spi_RD и внутренние переменные-счетчики процедуры Filtrate_long. На примере других функций я вижу, что используемые регистры для локальных переменных в процедурах, компилятор сохраняет в стек, при вызове внутри одной процедуры другой (с такими же регистрами). Иначе я вообще никогда не смог бы вызывать внутри процедур другие процедуры. Именно так происходит и тут. Просто количество параметров передаваемых в процедуру Spi_RD наверное большое и они вышли за регистры и компилятор о них забыл (мое предположение). Вот вызовы процедур с которыми я нашел пересечение переменных: Код bit Spi_RD(byte * ptr, byte * complete, word LEN, byte type, byte FIRST_SENT, bit cs);
signed long filtrate_long(signed long input_data); Пересеклись адреса следующих переменных type, FIRST_SENT с локальными переменными (счетчиками) внутри функции Filtrate_long. В данный момент локальные переменные функции Filtrate_long я объявил в области XDATA дабы они попросту ушли из карты памяти в другую область (остальные вроде как ен пересекаются). И все работает без глюков. Без наездов. Просто пытаюсь разобраться, что я делаю не так. И что мне следует сделать, чтобы такого не происходило впредь. Ведь я не исключаю того что такое же может произойти в области XDATA. Цитата(tag @ Dec 11 2008, 13:05)  Как известно памяти у 51 немного, плюс компилятор разработан так что локальные переменные сохраняет не на стеке, а либо в регистрах, либо в памяти (в этом вы можете убедится просмотрев руководство). В случае когда переменные располагаются в памяти линковщик может перекрывать область памяти локальных переменных одной подпрограммы и такую же область другой подпрограммы. Видимо так сделано с целью экономии памяти. Тогда, конечно подразумевается что эти фукции к примеру, не могут вызывать друг друга из своего тела. Так линковщик работает если ему не указать опцию nooverlay. Когда данная опция указана области локальных переменных подпрограмм не пересекаются и следовательно проблема порчи локальных переменных исчезает. Добрый день. Огромное вам спасибо. Мне кажется - это есть лекарство моей болезни. Так как симптомы вы описали точно. Черт, а ведь эта директива относится ко всему проекту. С ней области data не хватает  А для лечения локально, нужно делать глобальбные переменные. А что же делать с входыми данными процедур??? Тоже глобально??
Сообщение отредактировал AndreyS - Dec 11 2008, 12:11
--------------------
Удачи.
|
|
|
|
|
Dec 11 2008, 14:00
|
Знающий
   
Группа: Свой
Сообщений: 540
Регистрация: 16-08-07
Из: Владивосток
Пользователь №: 29 831

|
Цитата(AndreyS @ Dec 11 2008, 22:00)  Компилятор никогда не отображает локальные переменные на одни и теже адреса, если они пересекаются при вызове процедур (РАЗНЫХ ПРОЦЕДУР). Если переменные пересекаются (отображаются на одни и теже адреса) (РЕГИСТРЫ НАПРИМЕР), то компилятор при входе в такую процедуру сохраняет все эти регистры в стек. Если компилятор этого не делает - то это плохой компилятор. Анализирую код Keil'а он (Кейл) именно так и делает. Здесь позвольте с Вами не согласиться. Это относится не конкретно к Keil, а вообще к языку C. Локальные переменные, кроме того что они видны только внутри функции (блока), они еще имеют время жизни только на протяжении выполнения этой функции (блока). Ни в коем случае не гарантируется, что при очередном вызове функции локальная переменная будет иметь тоже значение, что было раньше. Цитата Если я в перерывании (или процедуре) использую вызов процедуры, то в прерывании, перед ее выполнением, сохряняются все регистры и PSW в стек. Если я неиспользую каких либо регистров (ну компилятор в процессе компиляции ничего не задействовал), то на входе он ничего не сохраняет. Для Кейла я это проверял. ,,, ....Если у меня есть ряд процедур, которые могут вызваться из прерывания и у них есть локальные переменные, то компилятор не отражает на адреса этих переменных ничего из других процедур. В данном примере я заметил пересекающиеся области... Чтобы не сохранять регистры лучше использовать using. А вот для этого случая - просто функции и функции вызываемой из прерывания, Keil действительно подкачал  , видимо у него нет такой проверки на перекрытие переменных  . Я когда-то тоже обжигался на этом. Теперь прерывания только наиболее короткие, без вызовов, с использованием отдельного банка памяти для прерываний одинакового приоритета. Цитата Правда весь листинг виден только в самом проце, в выходных файлах этого нет. А в *.LST разве в конце не расписаны адреса под переменные (при соответствующих галочках в настройках), или это не то? Код bit Spi_RD(byte * ptr, byte * complete, word LEN, byte type, byte FIRST_SENT, bit cs); Меня, честно говоря, пугают такие функции с огромным количеством входных переменных  . Не воспринимайте мои слова близко к сердцу. Это конечно не ошибка, просто я бы использовал структуру и передавал бы указатель на нее.
Сообщение отредактировал barabek - Dec 11 2008, 14:10
|
|
|
|
|
Dec 11 2008, 14:37
|

Местный
  
Группа: Участник
Сообщений: 235
Регистрация: 28-01-05
Из: Санкт-Петербург
Пользователь №: 2 276

|
Цитата(barabek @ Dec 11 2008, 17:00)  Здесь позвольте с Вами не согласиться. Это относится не конкретно к Keil, а вообще к языку C. Локальные переменные, кроме того что они видны только внутри функции (блока), они еще имеют время жизни только на протяжении выполнения этой функции (блока). Ни в коем случае не гарантируется, что при очередном вызове функции локальная переменная будет иметь тоже значение, что было раньше. Меня, честно говоря, пугают такие функции с огромным количеством входных переменных  . Не воспринимайте мои слова близко к сердцу. Это конечно не ошибка, просто я бы использовал структуру и передавал бы указатель на нее. Я согласен что локальные переменные имеют время жизни только на протяжении функции. Но при этом регистры то он в стек сохраняет (т.е. если я из функци вызову другую, то локальные переменные первой функции он сохранит в стек или будет использовать локальные переменные второй функции в другой области), а вот локальные переменные, что вылезли за диапазон регистров он в стек не сохраняет. Т.е. если я передаю в функцию большое количество параметров есть вероятность пересечения. Тут же у меня была проблемма с изменением ячейки. Я не понял почему это происходит (оставил для разбирательств на потом) просто завел внутри процедуры дублирующую локальную переменную (она видно отразилась в регистры) и в нее перебрасывал срузу при входе в процедуру данные из ихменяющейся переменной. Все заработало номарльно. Тогда я не врубился кто виноват (думал сам куда за диапазон выхожу), а теперь понял. Надо шерстить весь проект на предмет большого числа передаваемых параметров. Делать либо как у вас (заполнять структуру и передавать указатель. Просто я хотел унивирсальности, а так прийдется везде еще таскать обписание этой структуры.) либо урезать часть передаваемых параметров в функцию и переносить их например в глобальные. Обидно все это. Регистры сохраняет (так как знает что их портит), а часть используемых ячеек не сохраняет.
--------------------
Удачи.
|
|
|
|
Сообщений в этой теме
Lotor Пару вопросов по Си для MCS51 Jul 8 2007, 15:32 alcosar Цитата(Lotor @ Jul 8 2007, 18:32) Доброе ... Jul 8 2007, 19:51 Lotor Цитата(alcosar @ Jul 8 2007, 23:51) const... Jul 9 2007, 16:18  msn Цитата(Lotor @ Jul 9 2007, 19:18) Это-то ... Jul 10 2007, 21:25   zltigo Цитата(msn @ Jul 11 2007, 00:25) пишем...... Jul 10 2007, 22:57  Sir Jon Цитата(Lotor @ Jul 9 2007, 19:18) Это-то ... Sep 7 2007, 10:51   kolobok0 Цитата(Sir Jon @ Sep 7 2007, 14:51) ..Хор... Sep 7 2007, 11:18 SALOME Цитата(Lotor @ Jul 8 2007, 22:32) Доброе ... Jul 9 2007, 03:46 oran-be ЦитатаЭто-то понятно, но есть вагон и маленькая те... Jul 9 2007, 18:17 Lotor Цитата(oran-be @ Jul 9 2007, 22:17) ... Jul 9 2007, 19:21  Sergu Цитата(Lotor @ Jul 9 2007, 22:21) Еще воз... Jul 10 2007, 03:51   Lotor Цитата(Sergu @ Jul 10 2007, 07:51) удобно... Jul 10 2007, 16:53 silc alcosar: const и не должен помещать в ОЗУ. Вам нуж... Aug 10 2007, 14:57 Василий_Безкатегорийный Насчет побитового обращения к портам. Я пытаюсь ра... Sep 25 2007, 08:45    tag Цитата(barabek @ Dec 11 2008, 04:31) В эт... Dec 11 2008, 10:05     barabek Цитата(tag @ Dec 11 2008, 20:05) Уверяю в... Dec 11 2008, 10:53 AndreyS Люди!!! Помогите. Пока перебросил пере... Dec 10 2008, 10:57 Axel Если функция не написана, как реентерабельная (сло... Dec 10 2008, 17:37 AndreyS Добрый день.
Написал для прерывания специальную ф... Dec 12 2008, 10:38 Сергей Борщ Цитата(AndreyS @ Dec 12 2008, 12:38) И пе... Dec 12 2008, 12:03  c8051 Цитата(Сергей Борщ @ Dec 12 2008, 15:03) ... Dec 12 2008, 16:52   Сергей Борщ Цитата(c8051 @ Dec 12 2008, 18:52) c51.pd... Dec 12 2008, 18:37    AndreyS Цитата(Сергей Борщ @ Dec 12 2008, 21:37) ... Dec 13 2008, 20:34
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|