Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32 gcc lib printf улетает в HardFault_Handler
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
marka
Здравствуйте.

Суть проблемы...

Пытаюсь вызвать стандартный printf из stdio и после вызова вылетает в HardFault_Handler.

Запускал отладчик смотрел на каком месте падает...
На строчке ldrh r2, [r1, #12]

Код
        862 [1]    in ../../../../../../newlib/libc/stdio/vfprintf.c
0x8003934  <+0x0034>        51 46        mov    r1, r10
0x8003936  <+0x0036>        8a 89        ldrh    r2, [r1, #12]


Есть подозрения что что-то с линковкой (адреса путаются)... или флаги линковщику особенные нужно скармливать...

Да! Заранее конечно подготовил мин. набор функция для библиотеки _write, _read и другие. Линковка проходит нормально, не ругается это точно.

Хочу узнать ваши предположения. Может кто сталкивался с такой проблемой...

Кусок из makefile, то что касается линковщика:

Код
LD     =arm-none-eabi-ld

LIB_B       =/usr/lib/arm-none-eabi/newlib/armv6-m/
LIB_GCC =/usr/lib/gcc/arm-none-eabi/4.8.2/armv6-m/
LIB_OP    =-L$(LIB_B) -lc -lg -L$(LIB_GCC) -lgcc
LINKOP   =-T link.ld

AFOBJ= \
    startup_stm32f0xx.o \
    user_io.o \
    main.o \
    phisic.o

$(LD) $(AFOBJ)  $(LINKOP) $(LIB_OP) -o $(PBIN)$(NAMEPROJ).elf


Вот скрипт линкера (самописный):
CODE
MEMORY
{
FLASH(RX) : ORIGIN = 0x08000000, LENGTH = 64K
RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}

_Min_Heap_Size =1; /* required amount of heap */

SECTIONS
{
.isr_vector : ALIGN(4)
{
_start_isr_vector = .;
KEEP(*(.isr_vector))
_end_isr_vector = .;
. = 0xc8 - _end_isr_vector + ALIGN(2);
KEEP(*(.loop))
} > FLASH = 0xff

.text : ALIGN(4)
{
_start_text = .;
*(.text)
*(.text*)
KEEP(*(.data_flash))
_end_text = .;
} > FLASH

.rodata : ALIGN(4)
{
_start_rodata = .;
*(.rodata)
*(.rodata*)
_end_rodata = .;
} > RAM AT > FLASH

.data : ALIGN(4)
{
_start_data = .;
*(.data)
*(.data*)
_end_data = .;
} > RAM AT > FLASH

.bss : ALIGN(4)
{
_start_bss = .;
*(.bss)
*(.bss*)
_end_bss = .;
} > RAM

.heap :
{
. = ALIGN(4);
PROVIDE(end = .);
KEEP(*(.heap))

. = . + _Min_Heap_Size;
} > RAM
}

_size_rodata = SIZEOF(.rodata);
_size_data = SIZEOF(.data);
_size_bss = SIZEOF(.bss);

_start_rodata_copi = _end_text;
_start_data_copi = _end_text + _size_rodata;
_start_bss_copi = _end_text + _size_rodata + _size_data;
slavokhire5
Вероятно проблемы с не выровнянным доступом. В f0 серии этого нельзя делать. Падает на инструкции загрузки полуслова. Если пытаетесь взять полуслово с не четного адреса, то это и есть ваша проблема)
Tarbal
Какое содержимое регистров r1, r10 и r2?
marka
Большое спасибо что откликнулись)

Цитата(slavokhire5 @ Nov 27 2015, 01:43) *
Вероятно проблемы с не выровнянным доступом. В f0 серии этого нельзя делать. Падает на инструкции загрузки полуслова. Если пытаетесь взять полуслово с не четного адреса, то это и есть ваша проблема)


Цитата(Tarbal @ Nov 27 2015, 04:45) *
Какое содержимое регистров r1, r10 и r2?



Да, вы правы. младший бит установлен. Подскажите как это исправить ? Может в скрипте линкера я не правильно применяю ALIGN(4) ?

Код
        862 [1]    in ../../../../../../newlib/libc/stdio/vfprintf.c
0x800392c  <+0x0034>        51 46        mov    r1, r10         // r1 = 0x80000c9 r10 = 0x80000c9
0x800392e  <+0x0036>        8a 89        ldrh    r2, [r1, #12]


Спасибо.
AHTOXA
Стек должен быть выровнен на 8 байт. Проверьте это.
marka
Цитата(AHTOXA @ Nov 27 2015, 13:50) *
Стек должен быть выровнен на 8 байт. Проверьте это.


Я только инициализирую указатель стека (0x20001FFF). Как еще можно его выровнять ?
Сергей Борщ
Цитата(marka @ Nov 27 2015, 13:08) *
Я только инициализирую указатель стека (0x20001FFF).
Как давно 0x20001FFF стало кратным 8? Вам надо инициализировать числом 0x20002000
marka
Цитата(Сергей Борщ @ Nov 27 2015, 14:13) *
Как давно 0x20001FFF стало кратным 8? Вам надо инициализировать числом 0x20002000


Сделал. Не помогло.

Проверил отдельно загрузку полуслова... все работает.
В чем еще может быть дело ?
AHTOXA
Осей никаких не используете?
Ну и покажите, наконец, код.
marka
Цитата(AHTOXA @ Nov 27 2015, 20:40) *
Осей никаких не используете?
Ну и покажите, наконец, код.


Оси нет. Вот исходники ....Нажмите для просмотра прикрепленного файла

Уже все перепробовал sad.gif

Сейчас поставил затычку -lnosys для отладки. Если уходит в HardFault_Handler то зажигает светодиод.
marka
Цитата(marka @ Nov 27 2015, 21:11) *
Оси нет. Вот исходники ....Нажмите для просмотра прикрепленного файла

Уже все перепробовал sad.gif

Сейчас поставил затычку -lnosys для отладки. Если уходит в HardFault_Handler то зажигает светодиод.


Что подскажите ?
AHTOXA
Да непонятно.
Куда у вас должен выводить текст printf? Откуда выделяется память для кучи?
Почему вы вручную указываете пути к библиотекам?
Что делает вот эта строчка в линкерном скрипте:
Код
        . = 0xc8 - _end_isr_vector + ALIGN(2);

?
Что-то странное вы наворотили с bss_init(), я не понял идеи. Очень вероятно, что вылетает не из printf, a отсюда:
Код
void bss_init()
{
    void *p = 0x00;
    while(p++ != pEndIN) *((uint8_t *)pStartIN++) = 0x00;
}


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

ЗЫ. Кстати, для вашего контроллера с 64К флеша и 8К ОЗУ gcc-шный printf - довольно жирное решение.
marka
Цитата(AHTOXA @ Nov 28 2015, 20:00) *
Да непонятно.
Куда у вас должен выводить текст printf? Откуда выделяется память для кучи?
Почему вы вручную указываете пути к библиотекам?


Перед началом теста printf делал заглушки _write, _read и остальные (из вышей ссылки (находил раньше когда гуглил)) sm.gif
Но до них вызов даже не доходил, сразу падала уже... после вызова printf где то в глубине...
Ну а потом просто решил линковать -lnosys.

Да, malloc работает корректно с -lnosys Нужно было только end в скрипте линкера дописать.

Выделении памяти от end после bss

Код
    .heap :
    {
        . = ALIGN(4);
        PROVIDE(end = .);
        KEEP(*(.heap))
        . = . + _Min_Heap_Size;
        . = ALIGN(4);
    } > RAM


Цитата(AHTOXA @ Nov 28 2015, 20:00) *
Что делает вот эта строчка в линкерном скрипте:
Код
        . = 0xc8 - _end_isr_vector + ALIGN(2);

?


Да, это я эксперименты ставил sm.gif нужно убрать.

Цитата(AHTOXA @ Nov 28 2015, 20:00) *
Что-то странное вы наворотили с bss_init(), я не понял идеи. Очень вероятно, что вылетает не из printf, a отсюда:
Код
void bss_init()
{
    void *p = 0x00;
    while(p++ != pEndIN) *((uint8_t *)pStartIN++) = 0x00;
}


Ну тот просто заполнение нулями от pStartIN до заранее подсчитанного размера секции bss.

Это все работает отлично. Проблем нет. Не где не падает до применения printf. Как только вызываю printf то усе sm.gif упала.

Цитата(AHTOXA @ Nov 28 2015, 20:00) *
ЗЫ. Кстати, для вашего контроллера с 64К флеша и 8К ОЗУ gcc-шный printf - довольно жирное решение.


Да, возможно. Но это просто тест printf.
marka
Проблема решена sm.gif
А дело вот в чем было...
В скрипт линкера нужно было добавить секцию:
Код
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        . = ALIGN(8);
        __exidx_end = .;
    } > FLASH


Для чего она нужна... еще не знаю. Может вы знаете ?

И данные для копирования (инициализация секций rodata, data, bss) нужно уже брать с адреса __exidx_end.
Вот полный скрипт линкера:
CODE
MEMORY
{
FLASH(RX) : ORIGIN = 0x08000000, LENGTH = 64K
RAM(RWX) : ORIGIN = 0x20000000, LENGTH = 8K
}

__ram_end = 0x20000000 + 8K;

/*
.text — скомпилированный машинный код;
.rodata — аналог .data для неизменяемых данных;
.data — глобальные и статические переменные;
.bss — глобальные и статические переменные, которые при старте содержат нулевое значение.

.comment — информация о версии компилятора;
.ARM.attributes — ARM-специфичные атрибуты файла.
*/

_Min_Heap_Size =1; /* required amount of heap */

SECTIONS
{
.isr_vector :
{
. = ALIGN(4);
_start_isr_vector = .;
KEEP(*(.isr_vector))
_end_isr_vector = .;
. = ALIGN(4);
_start_loop = .;
KEEP(*(.loop))
. = ALIGN(4);
_end_loop = .;
} > FLASH = 0xff

.text :
{
. = ALIGN(4);
_start_text = .;
*(.text)
*(.text*)
. = ALIGN(4);
_start_data_flash = .;
KEEP(*(.data_flash))
. = ALIGN(8);
_end_data_flash = .;
_end_text = .;

} > FLASH

.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
. = ALIGN(8);
__exidx_end = .;
} > FLASH

.rodata :
{
. = ALIGN(4);
_start_rodata = .;
*(.rodata)
*(.rodata*)
. = ALIGN(4);
_end_rodata = .;
} > RAM AT > FLASH

.data :
{
. = ALIGN(4);
_start_data = .;
*(.data)
*(.data*)
. = ALIGN(4);
_end_data = .;
} > RAM AT > FLASH

.bss :
{
. = ALIGN(4);
_start_bss = .;
*(.bss)
*(.bss*)
. = ALIGN(4);
_end_bss = .;
} > RAM

.heap :
{
. = ALIGN(4);
_start_heap = .;
PROVIDE(end = .);
KEEP(*(.heap))
. = . + _Min_Heap_Size;
. = ALIGN(4);
_end_heap = .;
} > RAM
}

_size_rodata = SIZEOF(.rodata);
_size_data = SIZEOF(.data);
_size_bss = SIZEOF(.bss);

_start_rodata_copi = __exidx_end;
_start_data_copi = __exidx_end + _size_rodata;
_start_bss_copi = __exidx_end + _size_rodata + _size_data;


Теперь камушек не падает sm.gif
Сергей Борщ
.rodata класть в ОЗУ не нужно.
marka
Цитата(Сергей Борщ @ Nov 29 2015, 01:00) *
.rodata класть в ОЗУ не нужно.


Ну не обязательно. Если нужно во флешь то .data_flash и все дела sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.