Перейти к содержанию
    

STM32L0 HardFault: заморочки с выравниванием

Есть какие то ограничения в ядре, приводящие к HardFault?

 

Пришлось в одной функции привести указатель типа uint8_t* к типу uint32_t* изза чего получил HardFault.

 

В STM32F4 камне тот же самый код работает нормально.

Почему же M0+ вылетает в HardFault?

Изменено пользователем k000858

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему же M0+ вылетает в HardFault?
Потому что не поддерживает невыровненный доступ.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Потому что не поддерживает невыровненный доступ.

можно поподробнее?

пока все проблемы выравнивая обходил стороной, проектов на M0+ минимум

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нужно гарантировать, что uint32_t* указывает на переменную, расположенную по адресу, кратному 4.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

можно поподробнее?
PM0223: STM32L0 Series Cortex®-M0+ programming manual, искать словосочетание "unaligned access"

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нужно гарантировать, что uint32_t* указывает на переменную, расположенную по адресу, кратному 4.

а, вот оно что. теперь более менее понимаю.

 

 

буфер в котором содержится нужное мне 32-битное значение uint8_t buf[100];

указатель на место, в котором содержится значением uint8_t* ptr = &buf[5];

 

на Cortex-M4 не заморачивался и делал вот так printf("val = %lu\n", *(uint32_t*)ptr);

на Cortex-M0+ такая запись приводит к HardFault'у. Причину теперь понимаю хорошо, и как не получать такой эффект тоже.

 

Пока сделал вот так:

uint8_t value[4];
value[0]    = *ptr;
value[1]    = *(ptr + 1);
value[2]    = *(ptr + 2);
value[3]    = *(ptr+ 3);
uint32_t val    = (value[0]) | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
printf("val = %lu\n", val);

 

но чувствую, можно сделать это поизящнее. Подскажите красивый способ получения доступа к 32-битному значению

Изменено пользователем k000858

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#pragma pack(push, 1)
struct _input {
uint32_t Value;
};
#pragma pack(pop)

struct _input * I = (struct _input *) ptr;
printf("val = %lu\n", I->Value);

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#pragma pack(push, 1)
struct _input {
uint32_t Value;
};
#pragma pack(pop)

struct _input * I = (struct _input *) ptr;
printf("val = %lu\n", I->Value);

да, спасибо, такой способ вполне подойдет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

да, спасибо, такой способ вполне подойдет.

Отпишитесь о результате.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... или более каноничный через memcpy.

uint32_t value;
memcpy(&value, ptr, sizeof(value));
printf("val = %lu\n", value);

Он вам кстати еще много где пригодится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... или более каноничный через memcpy.

uint32_t value;
memcpy(&value, ptr, sizeof(value));
printf("val = %lu\n", value);

Он вам кстати еще много где пригодится.

заработали оба способа

второй способ понравился даже больше. еще раз спасибо, теперь мне тема выравнивания еще более понятна.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Допустим, memcpy умеет правильно обращаться по невыровненному адресу. Или тупо байтами копирует. Но как помогает приведение указателя к указателю на выровненную структуру? От этого положение данных не меняется же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

... или более каноничный через memcpy.

uint32_t value;
memcpy(&value, ptr, sizeof(value));
printf("val = %lu\n", value);

Он вам кстати еще много где пригодится.

Если уж мы тут образованием занимаемся, то более кошерно формат указывать вот так:

uint32_t value;
memcpy(&value, ptr, sizeof(value));
printf("val = %" PRIu32 "\n", value);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

но чувствую, можно сделать это поизящнее. Подскажите красивый способ получения доступа к 32-битному значению

Если компилятор поддерживает соответствующий префикс, создать пакованные типы:

typedef __packed u16 u16p8;
typedef __packed s16 s16p8;
typedef __packed u32 u32p8;
typedef __packed s32 s32p8;
typedef __packed u64 u64p8;
typedef __packed s64 s64p8;

либо, если в компиляторе нет соответствующего префикса, создать соотв. классы и перегрузить в них операторы присваивания и приведения типа:

struct u32p8 {
  u8 bytes[4];
  operator u32() const { return u32load(&bytes); }
  u32p8 & operator =(u32 val) { u32save(&bytes, val); return *this; }
};

где: u32load() и u32save() - макросы, которые на процессоре поддерживающем невыровненный доступ определены просто как чтение или запись значения по этому адресу, а на процессоре не поддерживающем невыровненный доступ - они осуществляют побайтное чтение/запись слова.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...