реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Переполнен стек
_trunk_
сообщение Sep 29 2011, 11:35
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 26
Регистрация: 21-09-11
Пользователь №: 67 308



Добрый день. Пишу программу на С для Attiny25. Результат моделирования в Proteus'e таков: несколько секунд все идет нормально, потом моделирование останавливается, появляется ошибка - Pop Program stack: SP is not initialized. Насколько я понимаю, в этот момент переполняется стек. Подскажите, каким образом выйти из этой ситуации?
Go to the top of the page
 
+Quote Post
kovigor
сообщение Sep 29 2011, 13:33
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(_trunk_ @ Sep 29 2011, 14:35) *
Подскажите, каким образом выйти из этой ситуации?


Я не знаю, что у вас за адача, но если она не запредельно тяжела для вашего МК, то можно попробовать вот что.
Увеличить стек. Отказаться от использования рекурсии (если используете) ...

Сообщение отредактировал kovigor - Sep 29 2011, 13:35
Go to the top of the page
 
+Quote Post
_trunk_
сообщение Sep 29 2011, 14:26
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 26
Регистрация: 21-09-11
Пользователь №: 67 308



рекурсии не использую. а как увеличить стек?
Go to the top of the page
 
+Quote Post
kovigor
сообщение Sep 29 2011, 14:43
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(_trunk_ @ Sep 29 2011, 17:26) *
рекурсии не использую. а как увеличить стек?


А прерывания используете ?
Стек можно увеличить в настройках проекта через меню вашей среды разработки. Откройте проект и пройдитесь по меню ...
Go to the top of the page
 
+Quote Post
_trunk_
сообщение Sep 29 2011, 15:13
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 26
Регистрация: 21-09-11
Пользователь №: 67 308



да, прерывание использую. выход из ситуации нашел. в обработчике прерываний у меня объявлялся массив. этот массив сделал глобальным и стека стало хватать. по меню пройдусь) спасибо за помощь)
Go to the top of the page
 
+Quote Post
777777
сообщение Sep 30 2011, 12:10
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(_trunk_ @ Sep 29 2011, 19:13) *
да, прерывание использую. выход из ситуации нашел. в обработчике прерываний у меня объявлялся массив. этот массив сделал глобальным и стека стало хватать. по меню пройдусь) спасибо за помощь)

Интересное решение проблемы. Особенно если учесть, что убрав массив из стека, ты поместил его в RAM, в котором и находится стек. Как же его стало хватать?
Go to the top of the page
 
+Quote Post
paskal
сообщение Sep 30 2011, 16:07
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 352
Регистрация: 29-10-06
Из: Тула
Пользователь №: 21 769



Цитата(777777 @ Sep 30 2011, 16:10) *
Интересное решение проблемы. Особенно если учесть, что убрав массив из стека, ты поместил его в RAM, в котором и находится стек. Как же его стало хватать?

Очевидно потому что не хватало конкретно стека, а не рамы.
Go to the top of the page
 
+Quote Post
xemul
сообщение Sep 30 2011, 16:14
Сообщение #8



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(_trunk_ @ Sep 29 2011, 19:13) *
в обработчике прерываний у меня объявлялся массив. этот массив сделал глобальным и стека стало хватать.

В массив в прерывании Вы, по-видимому, что-то пишете, поэтому не забудьте объявить его volatile.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 30 2011, 18:21
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(xemul @ Sep 30 2011, 19:14) *
В массив в прерывании Вы, по-видимому, что-то пишете, поэтому не забудьте объявить его volatile.


Зачем массив далать volatile?
Раньше он объявлялся как локальная переменная.
Значит использовался только в прерывании.
И следовательно volatile не нужен.
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 1 2011, 22:15
Сообщение #10


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(xemul @ Sep 30 2011, 19:14) *
В массив в прерывании Вы, по-видимому, что-то пишете, поэтому не забудьте объявить его volatile.

volatile можно ставить на семафор взводимый в прерывании, который говорит о том, что данные поменялись, но никак не на сами данные - иначе это равносильно тотальному отключению оптимизации.
Go to the top of the page
 
+Quote Post
777777
сообщение Oct 5 2011, 04:02
Сообщение #11


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(paskal @ Sep 30 2011, 20:07) *
Очевидно потому что не хватало конкретно стека, а не рамы.

Это не столь очевидно. sm.gif Стек находится в RAM-е, у него нет отдельного пространства. И если ты перенесешь массив из стека и сделаешь глобальной переменной, то свободного места в ОЗУ обльше не станет.
Go to the top of the page
 
+Quote Post
Абырвалг
сообщение Oct 7 2011, 04:57
Сообщение #12


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 23-08-06
Пользователь №: 19 752



Цитата(_trunk_ @ Sep 29 2011, 20:13) *
да, прерывание использую. выход из ситуации нашел. в обработчике прерываний у меня объявлялся массив. этот массив сделал глобальным и стека стало хватать. по меню пройдусь) спасибо за помощь)


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

Еще я бы все таки попробовал разобраться с размером стека, а после сравнил оба варианта по размеру и быстродействию. На разных процессорах и для разных размеров массива результаты могут быть разными.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 7 2011, 09:22
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (defunct @ Oct 2 2011, 01:15) *
volatile можно ставить на семафор взводимый в прерывании, который говорит о том, что данные поменялись, но никак не на сами данные - иначе это равносильно тотальному отключению оптимизации.
Спорно. Спорили тут полтора года назад: http://electronix.ru/forum/index.php?s=&am...st&p=747603. С наступлением эры LTO (link-time optimization) в gcc может стать чертовски актуально.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 7 2011, 21:55
Сообщение #14


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Сергей Борщ @ Oct 7 2011, 12:22) *
Спорно. Спорили тут полтора года назад: http://electronix.ru/forum/index.php?s=&am...st&p=747603. С наступлением эры LTO (link-time optimization) в gcc может стать чертовски актуально.

Если насчет "head" я могу согласиться, то насчет записи в буфер уж никак нет. У компилятора нет повода менять действия местами - так как разрешение прерываний есть volatile операция:

# define sei() __asm__ __volatile__ ("sei" :: )

Можно ее считать программным data sync barrier'ом. Volatile на асм инструкцию однозначно указывает компилятору, что все действия описанные до этой инструкции должны быть завершены. Если была запись в буфер, то компилятор не имеет право отложить ее за пределы volatile инструкции. В то же время объявив данные буфера как volatile, Вы мешаете компилятору отложить запись до удобного момента. Что это за удобный момент, - например, до разрешения прерываний в буфер может быть положено что-то еще, и на ARM логично было бы сгруппировать все записи в одну burst инструкцию. Так вероятно и поступил бы компилятор, не объяви Вы каждое слово сторейджа как volatile.

Ниже привожу функцию:

Код
foo(void)
{
    int a = read_something_not_critical_and_slow();
    U32 iMask = ILock(); // запрет прерываний
    int b = read_something_critical_fast();

    ....
}


Я лично на 100% уверен, что действие "read_something_not_critical_and_slow" произойдет строго до запрета прерываний, а действие "read_something_critical_fast" произойдет строго после запрета прерываний. Если какой-то оптимизатор соптимизирует иначе, то он ничего не соображает в оптимизации. Так откуда же взялись сомнения насчет записи в буфер? sm.gif

Цитата
Ради экономии пары volatile и одной временной переменной?

Вы сталкивались с системами где RAM access time >50 clk для одно-тактового CPU? (для систем с DRAM это типично)
пара лишних volatile может стоит >50% ресурсов проца.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 8 2011, 08:59
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (defunct @ Oct 8 2011, 00:55) *
Volatile на асм инструкцию однозначно указывает компилятору, что все действия описанные до этой инструкции должны быть завершены. Если была запись в буфер, то компилятор не имеет право отложить ее за пределы volatile инструкции.
Этот момент для меня не совсем ясен. Надо обдумать. В той ветке ReAl приводил пример, когда такая инструкция не мешала перенести запись в не-volatile переменную. И я не готов ответить, кто прав в этом случае - вы или компилятор.
QUOTE (defunct @ Oct 8 2011, 00:55) *
В то же время объявив данные буфера как volatile, Вы мешаете компилятору отложить запись до удобного момента. Что это за удобный момент, - например, до разрешения прерываний в буфер может быть положено что-то еще, и на ARM логично было бы сгруппировать все записи в одну burst инструкцию. Так вероятно и поступил бы компилятор, не объяви Вы каждое слово сторейджа как volatile.
Боюсь, с учетом сказанного выше, на данный момент не существует способа объяснить компилятору допустимость этого.

QUOTE (defunct @ Oct 8 2011, 00:55) *
Я лично на 100% уверен, что действие "read_something_not_critical_and_slow" произойдет строго до запрета прерываний, а действие "read_something_critical_fast" произойдет строго после запрета прерываний. Если какой-то оптимизатор соптимизирует иначе, то он ничего не соображает в оптимизации.
Я, напротив, на 100% уверен, что компилятор может сделать иначе и с оптимизацией у него все в порядке. Если тело этих read_... ему доступно и оно не имеет побочных эффектов - то имеет полное право.

QUOTE (defunct @ Oct 8 2011, 00:55) *
Вы сталкивались с системами где RAM access time >50 clk для одно-тактового CPU? (для систем с DRAM это типично) пара лишних volatile может стоит >50% ресурсов проца.
Нет, не сталкивался. И точно также как и вы против использования лишних volatile. Мы лишь расходимся в критериях опредения, который именно считать лишним.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 8 2011, 23:18
Сообщение #16


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Сергей Борщ @ Oct 8 2011, 11:59) *
Я, напротив, на 100% уверен, что компилятор может сделать иначе и с оптимизацией у него все в порядке. Если тело этих read_... ему доступно и оно не имеет побочных эффектов - то имеет полное право.
Значит фтопку такой компилятор. Побочный эффект - прерывания будут запрещены дольше чем требуется либо не тогда когда нужно! Volatile инструкция как раз и указывает компилятору на то, что изменение порядка следования действий влечет к непредсказуемому результату.

Допустим компилятор видит, что расчет переменной "a" состоит из расчета переменной "b" плюс какие-то длительные дополнительные действия. Пусть эффективность функции "foo" будет выше если вначале расчитать значение переменной "b", а затем значение переменной "a". Но увеличив эффективность функции можно убить эффективность/функциональность всей системы, если поменяется порядок следования volatile инструкции. (я не зря в примере нарисовал всего три действия, перестановка расчета любой из переменных - выглядит как перестановка запрета прерываний)!

Если вдруг заметите, что gcc при каких-то опциях оптимизации меняет порядок следования volatile инструкции, - стоит репортить баг и пусть фиксят компилятор. И нам дайте знать в какой версии такое имеет место быть, чтобы ее не пользовать! )

Цитата(Сергей Борщ @ Oct 8 2011, 11:59) *
Боюсь, с учетом сказанного выше, на данный момент не существует способа объяснить компилятору допустимость этого.

Очень жаль, что они тогда оптимизируют в gcc непонятно. burst инструкция (STRM) при работе с DDR/SDRAM будет до 8 крат быстрее в сравнении с одиночными STR.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 10 2011, 07:13
Сообщение #17


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (defunct @ Oct 9 2011, 02:18) *
Если вдруг заметите, что gcc при каких-то опциях оптимизации меняет порядок следования volatile инструкции, - стоит репортить баг и пусть фиксят компилятор.
volatile как раз говорит о побочном эффекте. Я же написал - если содержимое этих функций не имеет побочных эффектов. И если в этих функциях нет volatile и нет вызова внешних функций - компилятор имеет право. А volatile вы сами рекомендуете в них убрать.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 10 2011, 21:39
Сообщение #18


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Сергей Борщ @ Oct 10 2011, 10:13) *
volatile как раз говорит о побочном эффекте. Я же написал - если содержимое этих функций не имеет побочных эффектов. И если в этих функциях нет volatile и нет вызова внешних функций - компилятор имеет право. А volatile вы сами рекомендуете в них убрать.

Так-с sm.gif
Расставим точки над i. Вот ваша цитата:

Цитата
Кстати, и буфер тоже должен быть volatile. В противном случае компилятор имеет полное право перенести запись в буфер после изменения Head и разрешения прерывания.

Я утверждаю - не должен он быть volatile, и рекомендую буфер и его элементы НЕ обьявлять как volatile. Пусть компилятор оптимизирует запись и обращения к буферу.

Потому что разрешение прерывания - есть volatile инструкция, и компилятор ни при каких условиях (если в нем нет багов) не имеет права изменять ее порядок появления в коде. Он не может перенести запись после разрешения прерываний как вы говорите, т.к. поменяется порядок volatile инструкции "sei". Кстати команда "RETI" в GCC также объявлена как volatile, поэтому сделать запись в буфер после выхода из обработчика прерывания компилятор тоже не имеет права.

Компилятор может лишь только вообще не писать в буфер, если обращений к нему больше нигде нет, но порядок следования команд, запись -> разрешение прерываний, на другой, он поменять не может!..
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 11 2011, 06:27
Сообщение #19


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (defunct @ Oct 11 2011, 00:39) *
Потому что разрешение прерывания - есть volatile инструкция, и компилятор ни при каких условиях (если в нем нет багов) не имеет права изменять ее порядок появления в коде. Он не может перенести запись после разрешения прерываний как вы говорите, т.к. поменяется порядок volatile инструкции "sei".
Вы не правы - он не может изменить ее порядок относительно других volatile-инструкций (или выражений с побочными эффектами). В противном случае он обязан был бы перед этой инструкцией выгрузить в ОЗУ содержимое всех регистров, в которых закешированы любые переменные. Но этого не происходит - достаточно посмотреть листинг. А вот если мы буфер сделаем volatile - он уже будет обязан сгрузить его в ОЗУ перед sei.

QUOTE (defunct @ Oct 11 2011, 00:39) *
Компилятор может лишь только вообще не писать в буфер, если обращений к нему больше нигде нет, но порядок следования команд, запись -> разрешение прерываний, на другой, он поменять не может!..
Мне кажется в этом вы ошибаетесь. Обратите внимание на пример ReAl в конце сообщения №36 той ветки.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 16 2011, 23:04
Сообщение #20


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Много всего написал, потом удалил, потому как не хочу втягиваться в бесконечный спор.
Оставлю только выжимку.
1. Компилятор не должен скидывать временные адреса/индексы, не должен скидывать автоматические переменные и т.д. Скидывать требуется ровно то что требуется, - переменную (или группу переменных) которая находится в защищенном блоке из volatile инструкций.
2. Примеры ReAl'а на мой взгляд непоказательны, в первый вставьте printf("%d",i); и всё станет на свои места, во втором - баг определенной одной версии компилятора.
3. Кто прав, кто неправ рассудит время. Если уж совсем по логике, - volatile перед переменной нужен только для тех переменных, которые не на 100% контроллируются кодом "видимым" компилятору, - а именно, изменяются другой программой, другим процессом, процессором, аппаратным/периферийным модулем. Переменные же которые изменяются кодом который компилятор генерит (в пределах одной программы), в т.ч. и изменяемые в прерываниях, - должны четко обрабатываться и без volatile.

PS: а почему же в той ветке нет продолжения? Никто на последний пост zltigo не ответил. За полтора года так и не удалось найти компилятор который бы выносил запись в буфер за пределы sei()? Стало быть вот и доказательство того, что таких компиляторов нет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 17 2011, 06:07
Сообщение #21


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (defunct @ Oct 17 2011, 02:04) *
Переменные же которые изменяются кодом который компилятор генерит (в пределах одной программы), в т.ч. и изменяемые в прерываниях, - должны четко обрабатываться и без volatile.
Ну это вы что-то сильно загнули. Тут за примером далеко ходить не нужно - очень много компиляторов выкидывают в основном цикле проверку не-volatile флага, который взводится в прерывании.

QUOTE (defunct @ Oct 17 2011, 02:04) *
За полтора года так и не удалось найти компилятор который бы выносил запись в буфер за пределы sei()? Стало быть вот и доказательство того, что таких компиляторов нет.
Да никто просто не искал. Я, например, использую volatile и спокоен, что подобного выноса не будет. Не использовать volatile рискуя нарваться на грабли ради того, чтобы найти такой компилятор как-то желания не возникает. Потому ветка и заглохла. И эта заглохнет.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
defunct
сообщение Oct 17 2011, 12:03
Сообщение #22


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(Сергей Борщ @ Oct 17 2011, 09:07) *
Ну это вы что-то сильно загнули. Тут за примером далеко ходить не нужно - очень много компиляторов выкидывают в основном цикле проверку не-volatile флага, который взводится в прерывании.

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

А вот способ выкинуть потребность в volatile - работать по указателю:

Код
typedef struct tagRING_BUFFER
{
     int put;
     int get;
     int size;
     U8 *storage;
} TRING, *PRING;

struct
{
    TRING RxRing;
    TRING TxRing;
} uart_ctrl;


static void ring_put( PRING pRing, U8 ch)
{
     U8 iMask = ILock();
     pRing->storage[ pRing->put++] = ch;
     if (pRing->put >= pRing->size)
         pRing->put = 0;
     IUnlock(iMask);
}

static U8 ring_get(PRING pRing, U8 *ch)
{
     U8 retval = FALSE;
     U8 iMask = ILock();
     if (pRing->put != pRing->get)
     {
         *ch = pRing->storage[pRing->get++];
         if (pRing->get >= pRing->size)
             pRing->get = 0;
         retval = TRUE;
     }
     IUnlock(iMask);
     return retval;
}


RX_ISR()
{
     ring_put( &uart_ctrl.RxRing, UDR);
}

TX_ISR()
{
     U8 ch;
     if ( ring_get( &uart_ctrl.TxRing, &ch))
         UDR = ch;
     ...
}

main()
{
     U8 ch;
     ...
     while(TRUE)
     {
          if (ring_get(&uart_ctrl.RxRing, &ch))
              ring_put(&uart_ctrl.TxRing, ch);
     }
}
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 19:13
Рейтинг@Mail.ru


Страница сгенерированна за 0.01619 секунд с 7
ELECTRONIX ©2004-2016