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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Hard Fault при выполнении malloc, но если выполняю пошагово - все ок
kt368
сообщение Dec 16 2013, 21:34
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Здравствуйте!
Есть функция, которой передаётся указатель на указатель на структуру (**pIndZwithZ). В самой функции указателю на структуру присваивается выделяемое malloc'ом пространство для некоторого количества таких структур. В итоге мне нужно чтоб функция с помощью указателя возвращала массив структур, их количество рассчитывается в самой функции. Так вот, в функции есть код:
Код
*pIndZwithZ = malloc(CalData_str.nZ * (sizeof(float) + sizeof(uint8_t)));
Если я ставлю breackpoint на следующую за ним строку, то при её выполнении происходит Hard Fault, причиной которого, как я понял, является "data bus error". Это видно из того, что SCB.CFSR становится равным 0x400. А если я точку останова ставлю на этом злополучной malloc'е, и далее выполняю пошагово, то никаких проблем не возникает. Heap'a точно хватает, пробовал увеличить - не помогло.
Посоветуйте, как можно пытаться бороться с проблемой?

P.S. LPC1758, Keil.
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Dec 16 2013, 23:57
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(kt368 @ Dec 16 2013, 16:34) *
Здравствуйте!
Есть функция, которой передаётся указатель на указатель на структуру (**pIndZwithZ). В самой функции указателю на структуру присваивается выделяемое malloc'ом пространство для некоторого количества таких структур. В итоге мне нужно чтоб функция с помощью указателя возвращала массив структур, их количество рассчитывается в самой функции. Так вот, в функции есть код:
Код
*pIndZwithZ = malloc(CalData_str.nZ * (sizeof(float) + sizeof(uint8_t)));
Если я ставлю breackpoint на следующую за ним строку, то при её выполнении происходит Hard Fault, причиной которого, как я понял, является "data bus error". Это видно из того, что SCB.CFSR становится равным 0x400. А если я точку останова ставлю на этом злополучной malloc'е, и далее выполняю пошагово, то никаких проблем не возникает. Heap'a точно хватает, пробовал увеличить - не помогло.
Посоветуйте, как можно пытаться бороться с проблемой?

P.S. LPC1758, Keil.

Было дело похожее, пошагово работало, в программе нет. Но вот не помню причину.
Стэка хватает?


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Dec 17 2013, 04:49
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Возможно дело в невыровненном доступе к памяти. Попробуйте вместо sizeof поставить просто число 16. Если падать перестанет, то делайте либо по размеру структуры размещение, либо по частям но с выравниванием.
Go to the top of the page
 
+Quote Post
kt368
сообщение Dec 17 2013, 06:03
Сообщение #4


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



А как проверить хватает ли стека?
Вот, что вижу в окне "Call Stack + Locals":
Прикрепленное изображение

Как узнать какой используется стек - аппаратный или программный? Может ли стек быть смешанный - сначала аппаратный, а по его истечении - программный?
Аргументом malloc'а пробовал ставить 16 - ничего не меняется.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 17 2013, 06:42
Сообщение #5


Гуру
******

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



Цитата(kt368 @ Dec 17 2013, 08:03) *
Как узнать какой используется стек - аппаратный или программный? Может ли стек быть смешанный - сначала аппаратный, а по его истечении - программный?
Что вы понимаете под "аппаратным" и "программным" стеками?


--------------------
На любой вопрос даю любой ответ
"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
kt368
сообщение Dec 17 2013, 08:36
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Я считал что аппаратный стек - это способность микроконтроллера при вызове одной функции из другой (или при выполнении прерывания) автоматически сохранять значения некоторых регистров, чтоб при возврате из функции или прерывания продолжилась нормальная работа программы. Например в PIC контроллерах он, кажется, использовался для сохранения адреса команды, следующей за вызовом данной функции или той комманды, которую необходимо выполнить после выхода из прерывания. В PIC-ах он был, кажется, имел 8 уровней.
А программный стек - это действия компилятора по сохранению этих же данных програмно, это требует дополнительное время, в отличие от аппаратного стека, но зато практически снимаются ограничения на размер стека. Хоть 100 уровней. Мне кажется логичным чтоб компилятор начинал использовать программный стек при переполнении аппаратного, хотя не уверен, может ли компилятор такое отследить.
Запутался, в общем, я со стеками.

Поместил вызов этой функции в самом начале main'a - поведение то же самое. Пошагово всё выполняется, а не пошагово - вылетает в Hard Fault.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 17 2013, 10:31
Сообщение #7


Гуру
******

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



Цитата(kt368 @ Dec 17 2013, 10:36) *
Например в PIC контроллерах он, кажется, использовался для сохранения адреса команды, следующей за вызовом данной функции или той комманды, которую необходимо выполнить после выхода из прерывания. В PIC-ах он был, кажется, имел 8 уровней.
Именно. При этом был абсолютно недоступен из программы и потому назывался аппаратным. У ARM такого стека нет, у него все стеки программно доступные. То есть вопрос теряет смысл.

Цитата(kt368 @ Dec 17 2013, 10:36) *
Поместил вызов этой функции в самом начале main'a - поведение то же самое. Пошагово всё выполняется, а не пошагово - вылетает в Hard Fault.
Раскручивайте содержимое стека, находите вызвавшую исключение команду, анализируйте содержимое задействованных в ней регистров.


--------------------
На любой вопрос даю любой ответ
"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
A. Fig Lee
сообщение Dec 17 2013, 12:37
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(kt368 @ Dec 17 2013, 03:36) *
Я считал что аппаратный стек - это способность микроконтроллера при вызове одной функции из другой (или при выполнении прерывания) автоматически сохранять значения некоторых регистров, чтоб при возврате из функции или прерывания продолжилась нормальная работа программы. Например в PIC контроллерах он, кажется, использовался для сохранения адреса команды, следующей за вызовом данной функции или той комманды, которую необходимо выполнить после выхода из прерывания. В PIC-ах он был, кажется, имел 8 уровней.
А программный стек - это действия компилятора по сохранению этих же данных програмно, это требует дополнительное время, в отличие от аппаратного стека, но зато практически снимаются ограничения на размер стека. Хоть 100 уровней. Мне кажется логичным чтоб компилятор начинал использовать программный стек при переполнении аппаратного, хотя не уверен, может ли компилятор такое отследить.
Запутался, в общем, я со стеками.

Поместил вызов этой функции в самом начале main'a - поведение то же самое. Пошагово всё выполняется, а не пошагово - вылетает в Hard Fault.

A.. Чето начинает всплывать впамяти. Прерывания используете? Хэндлеры все на месте? В прерываниях порядок?
Попробуйте запретить прерывание на время malloc();
Да, у меня прерывания шалили, а по шагам я в прерывания не попадал.

Первые 32 бита программы это значение указателя на стэк, вот и смотрите, достаточен ли он.


Еще я бы вызвал malloc(16); чисто для верности.
Но если в самом начале, подозрение на то, что стэк не инициализирован.
Гляньте линкер скрипт.


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
kt368
сообщение Dec 17 2013, 18:45
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Цитата(Сергей Борщ @ Dec 17 2013, 12:31) *
Раскручивайте содержимое стека, находите вызвавшую исключение команду, анализируйте содержимое задействованных в ней регистров.
Исключение, если я правильно пользуюсь инструментарием Keil'a, вызывает команда
Код
STR r0, [r5, #0x00]
Эта команда должна сохранять значение регистра r0 по адресу, указанному в регистре r5. Значение r0=0x100001D0, r5=0x0. Т.е. в память начиная с адреса 0x0 должно записаться значение 0x100001D0. Правильно я мыслю? А этого не происходит, смотрю на эту память через вкладку Memory Kil'a. Значения в указанном сегменте памяти не меняются.
И как обычно, при выполнении этой и последующих команд пошагово, всё ОК. А при установке breackpoint'а на следующей за этой команде - в регистре CFSR появляется число 0x400, что свидетельствует о "Imprecise data bus error". Об этом в "Application Note 209: Using Cortex-M3 and Cortex-M4 Fault Exceptions" пишут, что:

"
a data bus error has occurred, but the return address in the stack frame is not related to the instruction
that caused the error. When the processor sets this bit it does not write a fault address to SCB->BFAR.
This is an asynchronous fault. Therefore, if it is detected when the priority of the current process is
higher than the Bus Fault priority, the Bus Fault becomes pending and becomes active only when the
processor returns from all higher priority processes. If a precise fault occurs before the processor enters
the handler for the imprecise Bus Fault, the handler detects both IMPRECISERR set to 1 and one of the
precise fault status bits set to 1.
"
Т.е. произошла ошибка шины данных. Как узнать почему она произошла....

Цитата(A. Fig Lee @ Dec 17 2013, 14:37) *
Прерывания используете? Хэндлеры все на месте? В прерываниях порядок?
Попробуйте запретить прерывание на время malloc();
Запретил, не помогает.
Цитата(A. Fig Lee @ Dec 17 2013, 14:37) *
Первые 32 бита программы это значение указателя на стэк, вот и смотрите, достаточен ли он.
Подскажите, чо вы имеете в виду. Первые 32 бита вот: 0x02000004. Как зная это можно узнать размер стека?
Цитата(A. Fig Lee @ Dec 17 2013, 14:37) *
Еще я бы вызвал malloc(16); чисто для верности.
Но если в самом начале, подозрение на то, что стэк не инициализирован.
Гляньте линкер скрипт.
malloc(16) вызывал, все так же.
Линкер скрипт руками не создавал, он создался автоматически, я в ГУИ KEIL выставил требуемые настройки.
Самое интересное, что проблема только с эти malloc'ом, в программе есть несколько других динамических выделений памяти, с ними всё ОК.
Функция, внутри которой этот malloc принимает указатель на указатель на структуру:
Код
void SortZIndOnCurF (struct IndZwithZ_str ** pIndZwithZ, uint16_t freq);
Внутри этой функции я пытаюсь выделить память и сохранить указатель на неё следующим образом:
Код
*pIndZwithZ = malloc(16);
Так вот, тут и происходит ошибка.
НО если я внутри этой функции создаю указатель на структуру
Код
struct IndZwithZ_str * tt;
И указатель на динамически выделенную память присваиваю этой переменной (tt):
Код
tt = malloc(16);
То проблем с HardFault не возникает. Может, я как-то неправильно пытаюсь возвратить из функции динамически созданный внутри функции массив структур?
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Dec 17 2013, 19:30
Сообщение #10


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(kt368 @ Dec 17 2013, 13:45) *
Подскажите, чо вы имеете в виду. Первые 32 бита вот: 0x02000004. Как зная это можно узнать размер стека?

У вас нет стека.
Аддресс загружается в указатель стека: 0x04000002
всего 2 байта на стек.
Смотрите линкер скрипт, документацию, как установить размер стека.


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
kt368
сообщение Dec 17 2013, 21:22
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Цитата(A. Fig Lee @ Dec 17 2013, 21:30) *
Аддресс загружается в указатель стека: 0x04000002
всего 2 байта на стек.
Да вроде бы нет, наверное все-таки со стеком все нормально.
Размер стека я указываю в файле startup_LPC17xx.s, в нём сейчас указано
Код
Stack_Size      EQU     0x00007000
Пробовал указать
Код
Stack_Size      EQU     0x00000001
при этом вообще ни одна из функций в main'e не выполнялось, улетало в HardFault.
Приложил два hex файла, соответствующих этим случаям.

А возвращение динамического массива структур из функции (из-за чего и происходил HardFault) я переделал, теперь HardFault не вылетает, хотя не понятно, почему он раньше происходил. Сейчас функция возвращает просто указатель на этот массив, который внутри неё создаётся с помощью malloc. Теперь почему-то не глючит.
Прикрепленные файлы
Прикрепленный файл  hex.zip ( 77.76 килобайт ) Кол-во скачиваний: 5
 
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Dec 17 2013, 21:52
Сообщение #12


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Цитата(kt368 @ Dec 17 2013, 16:22) *
Да вроде бы нет, наверное все-таки со стеком все нормально.
Размер стека я указываю в файле startup_LPC17xx.s, в нём сейчас указано
Код
Stack_Size      EQU     0x00007000
Пробовал указать
Код
Stack_Size      EQU     0x00000001
при этом вообще ни одна из функций в main'e не выполнялось, улетало в HardFault.
Приложил два hex файла, соответствующих этим случаям.

А возвращение динамического массива структур из функции (из-за чего и происходил HardFault) я переделал, теперь HardFault не вылетает, хотя не понятно, почему он раньше происходил. Сейчас функция возвращает просто указатель на этот массив, который внутри неё создаётся с помощью malloc. Теперь почему-то не глючит.

Интересненько..
Cortex ы в первых 4х байтах имеют значение, которое надо загрузить в стэк пойнтер..
Может он потом инициализируется? Непонятно.
Если RAM начинается с 0x04000000, то 0х04000002 означает, что стэк всего 2 байта.
Может это не binary file был? Чего то я недопонимаю..

A! Так это же hex file. В binary должно быть как я говорил

Сообщение отредактировал A. Fig Lee - Dec 17 2013, 21:54


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 17 2013, 21:58
Сообщение #13


Гуру
******

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



Цитата(kt368 @ Dec 17 2013, 20:45) *
Эта команда должна сохранять значение регистра r0 по адресу, указанному в регистре r5. Значение r0=0x100001D0, r5=0x0. Т.е. в память начиная с адреса 0x0 должно записаться значение 0x100001D0. Правильно я мыслю?
Мыслите вы правильно. А вы уверены, что на нулевые адреса у вас отмаплено ОЗУ? Обычно туда отражена флешь, а запись в нее запрещена. Вот вам и исключение - попытка записи в память read-only.

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


--------------------
На любой вопрос даю любой ответ
"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
kt368
сообщение Dec 18 2013, 11:03
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135



Да, это были hex файлы. Для создания bin воспользовалься утилитой fromelf.exe, она сгенерировала каталог с тремя файлами, прикрепил его к сообщению.
Вот скрины настроек линкера, тут указаны регионы используемой памяти. Файл proj1.stc - Scatter файл, как я понял он из-за галочки "Use Mmemory Layout from Target Dialog" не используется, но на всякий случай я его тоже прикрепил. MAP-файл также прикрепил.
Спасибо за помощь!
Эскизы прикрепленных изображений
Прикрепленное изображение
Прикрепленное изображение
 

Прикрепленные файлы
Прикрепленный файл  proj1.bin.zip ( 25.23 килобайт ) Кол-во скачиваний: 8
Прикрепленный файл  proj1.sct.zip ( 415 байт ) Кол-во скачиваний: 9
Прикрепленный файл  proj1.map.zip ( 21.9 килобайт ) Кол-во скачиваний: 8
 
Go to the top of the page
 
+Quote Post
A. Fig Lee
сообщение Dec 18 2013, 13:54
Сообщение #15


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Странное, непонятное мне распределение IRAM на картинке (я правда в Keil не копенгаген).
Судя по даташиту, РАМ начинается с 0x20000000 и тянется 64 килобайта до 0х2000FFFF.
А тут на диалоге значения не вписываются во фрагмент.

Подождем, пока знающие люди прокомментируют


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post

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

 


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


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