|
Hard Fault при выполнении malloc, но если выполняю пошагово - все ок |
|
|
|
Dec 16 2013, 21:34
|
Местный
  
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Dec 16 2013, 23:57
|

Знающий
   
Группа: Участник
Сообщений: 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. Было дело похожее, пошагово работало, в программе нет. Но вот не помню причину. Стэка хватает?
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Dec 17 2013, 06:03
|
Местный
  
Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135

|
А как проверить хватает ли стека? Вот, что вижу в окне "Call Stack + Locals":
Как узнать какой используется стек - аппаратный или программный? Может ли стек быть смешанный - сначала аппаратный, а по его истечении - программный? Аргументом malloc'а пробовал ставить 16 - ничего не меняется.
|
|
|
|
|
Dec 17 2013, 08:36
|
Местный
  
Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135

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

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Dec 17 2013, 12:37
|

Знающий
   
Группа: Участник
Сообщений: 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); чисто для верности. Но если в самом начале, подозрение на то, что стэк не инициализирован. Гляньте линкер скрипт.
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Dec 17 2013, 18:45
|
Местный
  
Группа: Свой
Сообщений: 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 не возникает. Может, я как-то неправильно пытаюсь возвратить из функции динамически созданный внутри функции массив структур?
|
|
|
|
|
Dec 17 2013, 19:30
|

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

|
Цитата(kt368 @ Dec 17 2013, 13:45)  Подскажите, чо вы имеете в виду. Первые 32 бита вот: 0x02000004. Как зная это можно узнать размер стека? У вас нет стека. Аддресс загружается в указатель стека: 0x04000002 всего 2 байта на стек. Смотрите линкер скрипт, документацию, как установить размер стека.
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Dec 17 2013, 21:22
|
Местный
  
Группа: Свой
Сообщений: 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
|
|
|
|
|
Dec 17 2013, 21:52
|

Знающий
   
Группа: Участник
Сообщений: 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
--------------------
Верить нельзя никому, даже себе. Мне - можно.
|
|
|
|
|
Dec 17 2013, 21:58
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Dec 18 2013, 11:03
|
Местный
  
Группа: Свой
Сообщений: 454
Регистрация: 13-10-10
Из: Киев
Пользователь №: 60 135

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