Как стать автором
Обновить

Комментарии 24

Только для keil господ. Gcc нищеброды будут по прежнему пользоваться #define

Нее, "Gcc-нищеброды" задействуют linker scripts.

Блин, целую статью написали о том как переменную записать. Куда катится хабр?

volatile int *some_peirph = (uintptr_t)0x1234566;

всегда пользовался таким. И оно работает всюду. так как использует только стандартные (от слова standard) конструкции.

Заголовок неверный, не "как записать по адресу", а "как разместить по адресу". И второе возможностями только языка, без расширений, не решается.

Все бы ничего, но как подход gcc автор приводит код

#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000)

А это именно то, что я с Volatile написал

Если бы было

#define FLASH_SRCTOR_0 (*(Volatile int *)0x123456)

То код бы был равнозначный

Ваш код с volatile указателем решает другую задачу - пишет значение по адресу во время выполнения, что отлично подходит для записи в регистры периферии, но не во flash. Тогда как пример автора размещает значение по адресу на этапе компоновки, оно оказывается там ещё в прошивочном файле и зашивается программатором (для чего? к примеру, это может быть маркер наличия "основной" части прошивки для бутлоадера)

Упоминаний GCC в статье вообще нет, а данные #define - просто константы адресов секторов. Кода, использующего их, в статье также нет.

Вот. Сразу видно грамотный ответ.
Спасибо. Теперь у меня все встало на свои места

Кстати, тогда к вам вопрос, так как вы похоже чучше автора статьи в теме разбираетесь.
Как будет в итоге работать изначальный пример автора (переменная то не const)

uint32_t keyFlash __attribute__((at(0x08004000))) ;
...
{
KeyFlash =42;
}

Кейл будет какой-то инструментированный код делать чтобы во флеше перезаписать данные?

Не будет

Обратите внимание: в коде автора нет отдельного присваивания позже, у него — сразу в объявлении статическая инициализация, из неё никакого кода не генерируется вообще, просто в выходном elf появится секция с соответствующими адресом и содержимым, которая прошьётся во flash.
Ваш же код с отдельным присваиванием даст тот же результат, что и запись по указателю — сгенерируется код для записи значения по адресу уже во время исполнения (и точно так же не сработает).
То, что у автора там отсутствует const, хоть и не очень красиво, но результат в данном случае не изменит. Разница будет в типе секции (RW, а не RO) и в отсутствии дальнейших проверок компилятором (этой переменной дальше можно будет безрезультатно присваивать новые значения и компилятор не будет ругаться).

А давайте я целую статью напишу о том как прикастить целое число к указателю?

Я без компилятора строку писал. По памяти. Я думал, что общая идея понятна. А оказывается вот оно как.

А теперь перенесите эту переменную, например, на последнюю страницу Flash-памяти контроллера, чтобы при обновлении прошивки она не затиралась (в загрузчике программно защищаем эту последнюю страницу от записи или стирания).

я не понимаю проблемы. Адрес можно написать любой. хоть на последнюю страницу, хоть на первую, хоть на срединную.
и при обновлении прошивки ничего затираться не будет так как это просто адрес. Если нужно указать, что память RO - то используйте const. Точно также const будет работать и для всяких экстеншинов arm cc.
volatile int * const some_perf - если адрес не нужно менять. и нужно чтоб он фиксированный был.
const volatile int *some_perf - ecли это память RO и нужно только читать
const volatile int *const some_perif - если все сразу.

@catBasilio

уж будьте добры - напишите и скомпилируйте. Вообще не понимаю что вы предлагаете. Так что-ли?

volatile uint32_t p = (uint32_t)0x0800C000;

int main(void){
*p= 0xAAAAAAAA;
}

volatile uint32_t p = (uint32_t)0x0800C000;
int main(void){
*p= 0xAAAAAAAA;
}

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

То что на скриншоте - уже правильный код, и он должен работать.
Почему он не работает - это отдельный вопрос. Навскидку могу предположить:

  • Keil криво трэкает изменение содержимое памяти

  • Память по этому адресу - RO. и по какой-то причине не кидается исключение при попытке ее записи. Возможно нужно в какой-то регистр периферии скорфигурировать, чтобы эта память стала доступна на запить, но тут нужно больше контекста.

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

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

"Почему он не работает - это отдельный вопрос."

Нет, это не отдельный вопрос, а именно тема статьи. Прочтите пожалуйста ещё раз статью, пошагово повторите описанные в ней действия на реальном железе (хотя возможно Proteus тоже подойдёт), также можно попробовать взять железо в аренду. Вам предстоит разобраться и открыть для себя много нового. Можете также поробоватьть сделать упражнение. Спасибо за участие в обсуждении.

у меня нет железа, у меня нет kail. и я не хочу тратить время на выяснение, почему у ВАС оно не работает.

Нет, это не отдельный вопрос, а именно тема статьи

Код правильный работать он должен. и он делает именно то, что было написано в заголовке статьи, до того, как вы его переименовали.

если хотите разобраться то приведите пожалуйста ассемблерный код.

Так очевидно почему он не работает, потому что адрес указывает на read-only flash(ROM), который хотя и отображается в адресное пространство изменить нельзя. Работало бы если это был адрес в RAM.

Тогда почему эксепшин не кидается?

Наверняка потому, что это простенький микроконтроллер, без MMU и защиты памяти.

Этот код - не переменная по адресу, это указатель на адрес. Для переменной подошёл бы С++ синтакс:
volatile uintmax_t &some_periph = *(uintptr_t*)0x1234566

А что, в gcc/keil нет возможности указывать кусок программы как __code? По типу указателя uint8_t* __code p __at(0x123456789)?

Для слишком умных компиляторов существует #pragma used или __ attribute __ ((used))

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории