Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103RET6 уходит в HardFault_Handler
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
011119xx
Работаю в Keil 4. Пытаюсь инициализировать FAT следующей функцией:

Код
void MountDrive(void)
{
    uint32_t    TotSectors;
    uint32_t    DataSectors;
    uint32_t    FirstSector;
    struct    partrecord *pr;
    struct    bpb710 *bpb;
    int i;

    SectorBuffer = (uint32_t*) malloc(512);

    if (SectorBuffer == NULL)
    {
        return;
    }

    readsector(0, (uint8_t *)SectorBuffer);

            то что ниже не привожу, так как проблема возникает выше
}


SectorBuffer объявлено выше как:
Код
uint32_t    *SectorBuffer;


При этом при попытке прочитать сектор программа уходит в HardFault_Handler в файле stm32f10x_it.c и там зависает.

Если поменять код на такой:

Код
void MountDrive(void)
{
    uint32_t TotSectors;
    uint32_t DataSectors;
    uint32_t FirstSector;
    struct partrecord *pr;
    struct bpb710 *bpb;
    int i;
    uint8_t buffer[512];

    SectorBuffer = (uint32_t *)buffer;                            

    if (SectorBuffer == NULL)
    {
        return;
    }
      
    readsector(0, (uint8_t *)SectorBuffer);                        
}


то сектор читается и перехода в HardFault_Handler не происходит. Вопрос: почему не работает первый вариант кода? Что там не так?
zhevak
Могу ошибиться. Рассматривайте это как вариант поиска бага.

После получения значения, но перед использованием, Вы посмотреть значение SectorBuffer можете? Куда он указывает?

Единственное, что приходит в голову, что malloc возвращает не выровненный на границу слова указатель. А когда происходит обращение к памяти по этому указателю, возникает исключительная ситуация.
011119xx
SectorBuffer указывает на область ОЗУ по адресу 0x20000320. Иногда бывает другой адрес, но всегда четный.
Dron_Gus
Цитата(011119xx @ Feb 21 2011, 09:25) *
...но всегда четный.

А кратный 4?
011119xx
Да.
sonycman
А куча и стек имеют достаточный размер?

Вообще причины могут быть разные, смотря что там внутри readsector.
Вот что что, а выравнивание буфера для чтения сектора никак не должно быть обязательным.
011119xx
Цитата(sonycman @ Feb 21 2011, 14:54) *
А куча и стек имеют достаточный размер?


Вот этого я не знаю.

Код
static uint8_t readsector(uint32_t lba, uint8_t *buffer)
{
    if(lba == sector_in_buffer)                                
        return 0;                                    

    sector_in_buffer = lba;                                    
    return sd_readsector(lba, buffer);                        
}

int8_t sd_readsector(uint32_t lba, uint8_t *buffer)
{
    uint16_t i;

GPIO_ResetBits(SD_CS_PORT, PIN_CS_SD);                    

    if(sdhc_card)                                            
        sd_command(SD_READ_SINGLE_BLOCK, lba);                
    else                                                    
        sd_command(SD_READ_SINGLE_BLOCK, lba << 9);            
    
    if(sd_get_response() != 0)                                 
        {
            sd_send_dummys();                                 

            GPIO_SetBits(SD_CS_PORT, PIN_CS_SD);        
    
            return SD_ERROR;                                   
        }

    if(sd_get_datatoken() != SD_STARTBLOCK_READ)             
        {
            sd_send_dummys();                                 

            GPIO_SetBits(SD_CS_PORT, PIN_CS_SD);            

            return SD_ERROR;                                   
        }

    for(i = 0; i < 512; i++)                                 
        *buffer++ = SPI_byte(0xff);
        
    SPI_byte(0xff);                                            
    SPI_byte(0xff);                                            

    sd_send_dummys();                                         

    GPIO_SetBits(SD_CS_PORT, PIN_CS_SD);                    

    return SD_OK;                                                 
}
sonycman
Цитата(011119xx @ Feb 21 2011, 13:08) *
Вот этого я не знаю.

Ну как же, ты пользуешься выделением памяти из кучи (malloc), и не знаешь, как она инициализирована?

Для задания размеров стека и кучи в кейле можно воспользоваться табом Configuration Wizard под окошком текстового редактора.
Или же просто открыть стартап файл STM32F10x.s и в нём указать необходимые значения в строчках:
Stack_Size EQU ...
Heap_Size EQU ...
ViKo
А stdlib.h включен в исходный файл?

011119xx
Да. Дело было в стеке. У меня стоял размер 512 байт. Увеличил до 1024 и проблема исчезла. Спасибо за помощь. Но остался вопрос: какого же размера все-таки делать стек? А куча для чего нужна? У меня под нее сейчас 0 выделено.
sonycman
Цитата(011119xx @ Feb 22 2011, 06:42) *
Да. Дело было в стеке. У меня стоял размер 512 байт. Увеличил до 1024 и проблема исчезла. Спасибо за помощь. Но остался вопрос: какого же размера все-таки делать стек? А куча для чего нужна? У меня под нее сейчас 0 выделено.

Я обычно задаю под стек 4 килобайта.
Это не повредит, особенно, если работаешь с файлами или с форматированным выводом (printf и т.д.).
Потом уже можно уменьшить, если хватает с избытком.

Куча - это память для динамического выделения функциями malloc() и т.п.
Если в твоей программе это есть - будь любезен задать размер кучи.
Я стараюсь избегать, по возможности, работы с кучей и пользуюсь вместо этого статическими блоками памяти.
zhevak
Цитата(011119xx @ Feb 22 2011, 08:42) *
Да. Дело было в стеке. ... А куча для чего нужна? У меня под нее сейчас 0 выделено.

А сейчас у меня вопрос. Если в куче не осталось свободного пространства или она изначально равна нулю, то почему malloc() возвращает валидный указатеь, т.е. не NULL?

Вот жеж:
Код
    SectorBuffer = (uint32_t*) malloc(512);

    if (SectorBuffer == NULL)
...

для чего это делается?
Или я чего-то не догоняю sad.gif
011119xx
А может память выделяется не из кучи, а из стека?
zhevak
Цитата(011119xx @ Feb 22 2011, 13:24) *
А может память выделяется не из кучи, а из стека?

А разве такое возможно для malloc()? Это же нонсэнс!
ViKo
Цитата(zhevak @ Feb 22 2011, 10:44) *
А разве такое возможно для malloc()? Это же нонсэнс!

Скорее всего, для инициализации того, что выделено из кучи, используется стек.
zhevak
Цитата(ViKo @ Feb 22 2011, 14:02) *
Скорее всего, для инициализации того, что выделено из кучи, используется стек.

Вообще не представляю как это возможно!

У Вас есть указатель стека, который перемещается каждый раз при вызове продпрограмм. По этому указателю записываются адреса возвратов, локальные переменные и т.д.

И вот в какой-то момент одна из функций запрашивает кусочек памяти. Указатель сдвигается, т.к. следующий оператор, допустим вызов еще какой-нибудь функции... Пока все нормально. Потом, допустим, вы возвращаемся из нескольких вложенных функций, но при этом кусок памяти не отдаем системе. Он все еще нам нужен! Потом опяит следуют вызовы, которые приближают указатель стека к началу нашего выделенного участка памяти... Вы понимаете проблему? Кто-то же должен сказать стеку "Э-э, парень! Стоп! Дальше идет выделенный кусок памяти, ну-ка прыгай вверх на 512 байт"
ViKo
Цитата(zhevak @ Feb 22 2011, 11:26) *
Вообще не представляю как это возможно!

Допустим, создается локальный массив из 512 байтов. При его создании нужно его инициализировать, забить нулями.
У меня в функции, инициализирующей ЖКИ, использовался массив констант. Пока я не задал ему квалификатор static, этот массив сначала создавался в стеке.
zhevak
Цитата(ViKo @ Feb 22 2011, 14:51) *
У меня в функции, инициализирующей ЖКИ, использовался массив констант. Пока я не задал ему квалификатор static, этот массив сначала создавался в стеке.

Ну да, все правильно. static переводит переменную из разрядя автоматических (созданных) на стеке, в разряд статических, созданных в оперативе до запуска main(). Тут все понятно.

Но куча (heap)? Тут же совсем другие механизмы выделения памяти работают.
Или мы о чем с Вами говорим? У меня такое чувство, что о разном.
ViKo
Цитата(zhevak @ Feb 22 2011, 14:57) *
Ну да, все правильно. static переводит переменную из разрядя автоматических (созданных) на стеке, в разряд статических, созданных в оперативе до запуска main(). Тут все понятно.

Но куча (heap)? Тут же совсем другие механизмы выделения памяти работают.
Или мы о чем с Вами говорим? У меня такое чувство, что о разном.

У меня были константы (static const), и брались в этом случае из Flash.
Это, наверное, другое.
Вопрос, как дальше использовалась память, выделенная с помощью malloc. Я только предположил, что для инициализации используется стек.
А что, если самой malloc() требуется стек?
aaarrr
Цитата(zhevak @ Feb 22 2011, 10:27) *
А сейчас у меня вопрос. Если в куче не осталось свободного пространства или она изначально равна нулю, то почему malloc() возвращает валидный указатеь, т.е. не NULL?

Где этот нулевой размер heap задается у вас?
sonycman
Цитата(ViKo @ Feb 22 2011, 16:12) *
Вопрос, как дальше использовалась память, выделенная с помощью malloc. Я только предположил, что для инициализации используется стек.

Не думаю, что область памяти, выделяемая с помощью malloc() из кучи, хоть как то инициализируется.
Это уже забота программиста.
Задача malloc() - просто предоставить блок свободной памяти.
zhevak
Цитата(ViKo @ Feb 22 2011, 18:12) *
Я только предположил, что для инициализации используется стек.
А что, если самой malloc() требуется стек?

Неверное предположение. Извините.
Самой функции malloc() для работы наверняка требуется стек. Хотя я не смотрел на ее исходные коды, и поэтому могу ошибиться. Но это не важно -- нужен ей стек для ее переменных или нет. Важно, что когда функция возвращает управление, ее стековый кадр перестает существовать. А значит, что нас совершенно не касается, что там она у себя внутри делает (если она все делает согласно своему описанию). Не думайте, что выделение и освобождение памяти -- это что-то сверхъестественное. Там все достаточно просто и особого изврата нет. Изврат начинается на стороне программиста, когда тот пытается записать по адресу, память которого уже отдана в общий пул памяти (возвращена в кучу), или когда программист забывает вернуть эту память. Один раз не пид... можно. Но если прога в цикле забирает память и не возвращает? В конце концов прога когда-нибудь да исчерпает всю память. (Мне в этом отношении нравится Линуксовый подход. -- Пестня! Попробуйте сотряпать прогу, которая постепенно сжирает память и посмотрите на реакцию системы. Уверяю -- получите удовольствие! Хотя... извините, Остапа опять пенесло!)

Цитата(sonycman @ Feb 22 2011, 21:41) *
Не думаю, что область памяти, выделяемая с помощью malloc() из кучи, хоть как то инициализируется.
Это уже забота программиста.
Задача malloc() - просто предоставить блок свободной памяти.

Вот именно -- не инициализируется! И это единственное правильное решение. Зачем память инициализировать? Чем ее инициализировать? Нулем? 0xFF-ами? Чем??? -- Ну откуда malloc() знает, что там собирается делать программер. А поскольку любая инициализация так или иначе потребует процессорного времени, то зачем его трать, если нам нужна не такая, а какая-то другая инициализация? Вот поэтому malloc() только выделяет кусок памяти и более ничего не делает. Ну разве что перед тем как это сделать, она проверяет а вообще сможет-ли она выделить непрерывный кусок памяти запрошенного размера. Если сможет, то помечает его границы (записывает особые отметки в пограничные участки) и возвращает пользователю начальный адрес куска.

Но если вы по каким-либо причинам произведете запись сразу же за последним байтом выделенного участка, то вы сломаете структуру. Возможно, вы сможете еще писать-читать из выделенных участков памяти, но уже нормально воспользоваться механизмом выделения и возвращения (malloc-free) -- нет!

Хех. Меняю свой опыт на вашу молодость.
ViKo
Цитата(zhevak @ Feb 22 2011, 20:17) *
Неверное предположение. Извините.

Я ж не сказал, что сама malloc() инициализирует выделенную память, а что она инициализируется потом, когда функция, которая запросила память, начинает ее использовать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.