Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Hard Fault при выполнении malloc
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
kt368
Здравствуйте!
Есть функция, которой передаётся указатель на указатель на структуру (**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.
A. Fig Lee
Цитата(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.

Было дело похожее, пошагово работало, в программе нет. Но вот не помню причину.
Стэка хватает?
andrewlekar
Возможно дело в невыровненном доступе к памяти. Попробуйте вместо sizeof поставить просто число 16. Если падать перестанет, то делайте либо по размеру структуры размещение, либо по частям но с выравниванием.
kt368
А как проверить хватает ли стека?
Вот, что вижу в окне "Call Stack + Locals":
Нажмите для просмотра прикрепленного файла
Как узнать какой используется стек - аппаратный или программный? Может ли стек быть смешанный - сначала аппаратный, а по его истечении - программный?
Аргументом malloc'а пробовал ставить 16 - ничего не меняется.
Сергей Борщ
Цитата(kt368 @ Dec 17 2013, 08:03) *
Как узнать какой используется стек - аппаратный или программный? Может ли стек быть смешанный - сначала аппаратный, а по его истечении - программный?
Что вы понимаете под "аппаратным" и "программным" стеками?
kt368
Я считал что аппаратный стек - это способность микроконтроллера при вызове одной функции из другой (или при выполнении прерывания) автоматически сохранять значения некоторых регистров, чтоб при возврате из функции или прерывания продолжилась нормальная работа программы. Например в PIC контроллерах он, кажется, использовался для сохранения адреса команды, следующей за вызовом данной функции или той комманды, которую необходимо выполнить после выхода из прерывания. В PIC-ах он был, кажется, имел 8 уровней.
А программный стек - это действия компилятора по сохранению этих же данных програмно, это требует дополнительное время, в отличие от аппаратного стека, но зато практически снимаются ограничения на размер стека. Хоть 100 уровней. Мне кажется логичным чтоб компилятор начинал использовать программный стек при переполнении аппаратного, хотя не уверен, может ли компилятор такое отследить.
Запутался, в общем, я со стеками.

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

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

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

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

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


Еще я бы вызвал malloc(16); чисто для верности.
Но если в самом начале, подозрение на то, что стэк не инициализирован.
Гляньте линкер скрипт.
kt368
Цитата(Сергей Борщ @ 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 не возникает. Может, я как-то неправильно пытаюсь возвратить из функции динамически созданный внутри функции массив структур?
A. Fig Lee
Цитата(kt368 @ Dec 17 2013, 13:45) *
Подскажите, чо вы имеете в виду. Первые 32 бита вот: 0x02000004. Как зная это можно узнать размер стека?

У вас нет стека.
Аддресс загружается в указатель стека: 0x04000002
всего 2 байта на стек.
Смотрите линкер скрипт, документацию, как установить размер стека.
kt368
Цитата(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. Теперь почему-то не глючит.
A. Fig Lee
Цитата(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 должно быть как я говорил
Сергей Борщ
Цитата(kt368 @ Dec 17 2013, 20:45) *
Эта команда должна сохранять значение регистра r0 по адресу, указанному в регистре r5. Значение r0=0x100001D0, r5=0x0. Т.е. в память начиная с адреса 0x0 должно записаться значение 0x100001D0. Правильно я мыслю?
Мыслите вы правильно. А вы уверены, что на нулевые адреса у вас отмаплено ОЗУ? Обычно туда отражена флешь, а запись в нее запрещена. Вот вам и исключение - попытка записи в память read-only.

Покажите .map - похоже у вас действительно что-то не то с распределением памяти. То ли скрипт линкера не от этого процика, то ли на самом деле используется другой скрипт.
kt368
Да, это были hex файлы. Для создания bin воспользовалься утилитой fromelf.exe, она сгенерировала каталог с тремя файлами, прикрепил его к сообщению.
Вот скрины настроек линкера, тут указаны регионы используемой памяти. Файл proj1.stc - Scatter файл, как я понял он из-за галочки "Use Mmemory Layout from Target Dialog" не используется, но на всякий случай я его тоже прикрепил. MAP-файл также прикрепил.
Спасибо за помощь!
A. Fig Lee
Странное, непонятное мне распределение IRAM на картинке (я правда в Keil не копенгаген).
Судя по даташиту, РАМ начинается с 0x20000000 и тянется 64 килобайта до 0х2000FFFF.
А тут на диалоге значения не вписываются во фрагмент.

Подождем, пока знающие люди прокомментируют
kt368
Почему ж странное, вот скрин юзер мануала, у меня проц с 64 кб ОЗУ. Оно разбито на 2 секции, вот я их обе и использую.
Нажмите для просмотра прикрепленного файла
Первая область - начинается с адресса 0x10000000, имет длину 0х8000.
Вторая область начинается с адреса 0x20000000, и тоже имет длину 0х8000.
toweroff
По-любому в 0 записывать нельзя, если не было ремапа
0 - это начало Non-Volatile memory
kt368
Цитата(toweroff @ Dec 18 2013, 16:24) *
По-любому в 0 записывать нельзя, еслине было ремапа
0 - это начало Non-Volatile memory

Это понятно, почему ж мне компилятор такой асм код выдал?
A. Fig Lee
Цитата(kt368 @ Dec 18 2013, 09:25) *
Это понятно, почему ж мне компилятор такой асм код выдал?

А какой был "С code", который скомпилировался в асм?
Может там собака порылась?
toweroff
Цитата(kt368 @ Dec 18 2013, 18:25) *
Это понятно, почему ж мне компилятор такой асм код выдал?

скаттр странный. Load Region - это та область, которая пишется (располагается, в случае заливки в ОЗУ) во флеш-память
потом, после старта, С-библиотеки разворачивают оттуда код, если это было указано, задают значения Zero-Init областям и т.д.
Я вот вижу два Load-Region - зачем? Есть в этом сокральный смысл?

Вообще, без кода, сложно что-то говорить. В программе нужно смотреть, почему вы (не компилятор!) обращается с записью по нулевому адресу
kt368
Я уже немного переделал СИ-шные файлы, и глюки перестали наблюдаться.
А скаттр файл по-идее же сейчас не используется, т.к. на вкладке "Linker" окна "Options for target" я поставил галочку "Use Memory layout from Target Dialog".
А вот тут, на вкладке Target я же нормально задал параметры памяти?
Тут я хотел сделать, чтоб для программы использовалась ROM по с адресами 0x0...0x240 и 0xB000...0x80000.

И заодно ещё парочку вопросов.
Подскажите, пожалуйста, что значат галочки "default" в этом окне?
И галочка "Startup" - она говорит где размещать начальный код, который генерируется из файлы startup.s?

P.S. Просьба за мои ошибки сильно не пинать, с армами и кейлом только начинаю разбираться.
toweroff
Цитата(kt368 @ Dec 18 2013, 23:24) *
Я уже немного переделал СИ-шные файлы, и глюки перестали наблюдаться.
А скаттр файл по-идее же сейчас не используется, т.к. на вкладке "Linker" окна "Options for target" я поставил галочку "Use Memory layout from Target Dialog".
А вот тут, на вкладке Target я же нормально задал параметры памяти?
Тут я хотел сделать, чтоб для программы использовалась ROM по с адресами 0x0...0x240 и 0xB000...0x80000.

И заодно ещё парочку вопросов.
Подскажите, пожалуйста, что значат галочки "default" в этом окне?
И галочка "Startup" - она говорит где размещать начальный код, который генерируется из файлы startup.s?

P.S. Просьба за мои ошибки сильно не пинать, с армами и кейлом только начинаю разбираться.

давно уже не пользуюсь этим окном (в плане где и что размещать), свои скаттеры пишу сам
в документации на линкер все подробно разжевано, как там и из чего строится
на всякий случай приложу пару документов
Нажмите для просмотра прикрепленного файла
Нажмите для просмотра прикрепленного файла
вообще-то вся документация на сайте ARM так и ждет прочтения, более свежая sm.gif
Сергей Борщ
Цитата(kt368 @ Dec 18 2013, 21:24) *
Подскажите, пожалуйста, что значат галочки "default" в этом окне?
С Кейлом не работаю, но внизу виднеется кнопочка "Help". Что будет, если ее нажать?
kt368
С размещением в памяти уже вроде-бы разобрался (используя доки Кейла), пока через ГУИ, в следующем проекте постараюсь использовать скаттер файл.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.