Jump to content

    
syoma

Переполнение стека в 8051 - как узнать?

Recommended Posts

Привет, 

Я понимаю, что архитектура уже давно устарела, но появился сабжевый вопрос. Прога на Си, много статических переменных, после последних изменений прога стала подглючивать на железе. Есть подозрение на переполнение стека, так как если для него отвести больше места - частота глюков уменьшается.  

Как узнать в этом ли проблема из самой программы? Средств отладки кроме самого камня на плате и осцилографов нет. 

Мониторить указатель стека или какие еще варианты?

 

Share this post


Link to post
Share on other sites

Ну да, мониторинг. Если средства позволяют, можно задействовать аналог "стековой канарейки".
При переполнении вызовется специальный callback, где можно будет дернуть ножкой. Но накладные расходы увеличатся.

Share this post


Link to post
Share on other sites

В стародавние времена память под стек заполняли однотипными значениями. Программу гоняли некоторое время в разных режимах. Затем - останавливали и смотрели на значения ячеек памяти, выделенной под стек. Так в первом приближении определялся потребный размер стека.

Share this post


Link to post
Share on other sites

Добавил в программу вывод максимального значения регистра указателя стека SP и получил интересный прикол:

Проглядывая листинг после компилятора, вижу, что стек используется только в функциях обработки прерываний. Т.е. там стоит такое:

T2_int:
	PUSH	PSW
	PUSH	ACC
	PUSH	DPH
	PUSH	DPL
	PUSH	B
	PUSH	_R
	PUSH	_R+1
	PUSH	_R+2
	PUSH	_R+3
	PUSH	_R+4
	PUSH	_R+5
	PUSH	_R+6
	PUSH	_R+7

Ну и при возвращении из них, соответственно:

POP	_R+7
	POP	_R+6
	POP	_R+5
	POP	_R+4
	POP	_R+3
	POP	_R+2
	POP	_R+1
	POP	_R
	POP	B
	POP	DPL
	POP	DPH
	POP	ACC
	POP	PSW
	RETI

Т.е. это 13 байт + в стек пихается адрес возврата - 2 байта Program Counter(PC). Т.е. всего 15 байт.

Больше PUSH и POP не используются нигде в программе - я проверял все листинги.

У меня два уровня вложенности/приоритета прерываний (8051 больше не позволяет), т.е получается, что в худшем случае достаточная величина стека должна быть: 15(регистры и PC основной программы при первом прерывании) + 15 (регистры и PC первого прерывания при прерывании с более высоким приоритетом) = 30 байт, что собственно мне линкер и показывает в дампе памяти, выделив аж 29 байт на стек.

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

Почему так? Это я что-то не учитываю, или это у меня прерывания неправильно работают?

 

 

Share this post


Link to post
Share on other sites
17 minutes ago, xvr said:

CALL'ы используются? Они тоже стек используют

 

Да, используются. Извиняюсь, мой провтык. Получается, что CALL тоже засовывает PC стек и в итоге выходит, что чтобы рассчитать нужную величину стека, нужно еще посчитать вложенность всех функций. Мда, задачка не из легких. 

 

 

Share this post


Link to post
Share on other sites

А локальные переменные в функциях где у вас живут ?

Или у вас два стека : программный стек и стек данных ? Как это например делает IAR для AVR.

Share this post


Link to post
Share on other sites
12 minutes ago, dimka76 said:

А локальные переменные в функциях где у вас живут ?

В data overlay сегменте памяти. По крайней мере  судя по листингу, обращение к ним не через стек.

Share this post


Link to post
Share on other sites
5 hours ago, dimka76 said:

А локальные переменные в функциях где у вас живут ?

Вот тут нашел еще один прикол - у меня в прерываниях используются локальные переменные, которые, как я понял, находятся тоже в data overlay. Что произойдет с ними, если прерывание с более высоким приоритетом прервет прерывание с низким приоритетом, в котором используются локальные переменные? Получается, что оно может испортить их значение?

Share this post


Link to post
Share on other sites
8 minutes ago, syoma said:

Вот тут нашел еще один прикол - у меня в прерываниях используются локальные переменные, которые, как я понял, находятся тоже в data overlay. Что произойдет с ними, если прерывание с более высоким приоритетом прервет прерывание с низким приоритетом, в котором используются локальные переменные? Получается, что оно может испортить их значение?

https://www.keil.com/support/man/docs/bl51/bl51_overlaying.htm

Share this post


Link to post
Share on other sites
20 hours ago, dimka76 said:

Почитал и поменял нафиг все локальные переменные в прерываниях на статические, так как не знаю насколько хорошо мой компилятор умеет этот overlay. Также заменил вызовы функций в прерываниях и где возможно в основной программе на их копии. Да, размер кода слегка увеличился, но думаю так будет надежнее.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.