HardEgor 68 5 августа, 2017 Опубликовано 5 августа, 2017 · Жалоба Потребление RTC - 5 uA. Если питание пропадет на сутки, чтобы RTC не сбросился..... Какие сутки? Вы же писали про ресеты, а не выключение питания. Если всё-таки выключение питания, то либо ставить батарейку, либо писать надо во флеш. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
turnon 1 5 августа, 2017 Опубликовано 5 августа, 2017 · Жалоба А зачем нужно это инкрементирование переменной? Возможно есть решения получше, которые Вы не замечаете. Как флаг для бутлоадера. В обычном режиме работы бутлоадер сразу запускает основную прошивку, а если есть флаг - то ожидает загрузки новой прошивки по USB. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 197 6 августа, 2017 Опубликовано 6 августа, 2017 · Жалоба Как флаг для бутлоадера. В обычном режиме работы бутлоадер сразу запускает основную прошивку, а если есть флаг - то ожидает загрузки новой прошивки по USB. Как я и думал.... :laughing: Вы смотрите совсем не туда. __no_init тут не нужен. Как не нужен и инкремент. __no_init для этого адреса должно быть в бутлоадере. Общий алгоритм таков: В бутлоадере объявляете этот адрес: __no_init char flag @ ...; при старте бутлоадера проверяете сначала флаг причины перезагрузки МК (искать где он нужно в даташите), если сброс был не по причине внутреннего WDT - передаёте управление в основную прогу. Если причина == внутренний WDT и flag != 0 - прошиваете прошивку и flag = 0. В основной программе объявляете: char flag @ ...; А когда нужно обновить прошивку делаете flag = 1 и вызываете срабатывание внутреннего WDT. Всё. PS: И я бы лучше указал имя определённой секции (в тех местах где ...), а не абсолютный адрес. А эту секцию в .icf смаппировал на нужный адрес. И в основной программе и в бутлоадере. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
turnon 1 6 августа, 2017 Опубликовано 6 августа, 2017 · Жалоба Вы смотрите совсем не туда. __no_init тут не нужен. Как не нужен и инкремент. __no_init для этого адреса должно быть в бутлоадере. Инкремент я привел для примера. В реальности там флаг, примерно как вы и описали (спасибо за подробный пример). К тому же флаг "подписан" контрольной суммой. Самое важное - что линкер под это выделяет место и что с очередной прошивкой там не окажется случайно не то что ожидаемо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 197 6 августа, 2017 Опубликовано 6 августа, 2017 · Жалоба Самое важное - что линкер под это выделяет место и что с очередной прошивкой там не окажется случайно не то что ожидаемо. В Вашем случае важно чтобы линкёр и в бутлоадере зарезервировал тот же самый адрес. Затереть может именно стартап-код бутлоадера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
turnon 1 6 августа, 2017 Опубликовано 6 августа, 2017 · Жалоба Какие сутки? Вы же писали про ресеты, а не выключение питания. Если всё-таки выключение питания, то либо ставить батарейку, либо писать надо во флеш. А разве батарейка нужна только для BkpSram? Часы же сбросятся. Даже и не представляю, какой сценарий использования без батарейки, но с конденсатором на Vbat. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба А есть ли стандартный, т.е. не выходящий за синтаксис С/С++ способ инициализации объекта по точно указанному адресу? Под объектом понимается объект данных любого типа - простого встроенного или составного пользовательского. Например целое число, перечисление, массив или структура. Вот пример кода, где объявляется и инициализируется константная структура с тремя полями данных. Из неё можно считывать данные - см. в main(). Но адрес её размещения в памяти выбирает линкер. #include <stdint.h> // Некая структура для примера struct MyConfig_st { uint8_t Field1; uint8_t Field2; uint8_t Field3; }; // Инициализация константной структуры const MyConfig_st MyConfig = {.Field1=0x66,.Field2=0x41,.Field3=0x7}; uint8_t tmp; // Сюда будем считывать данные структуры int main () { tmp=MyConfig.Field1; tmp=MyConfig.Field2; tmp=MyConfig.Field3; while(1); } Как штатными средствами C/C++ задать для этой структуры точный адрес? Я могу сделать указатель на неё и присвоить ему значение адреса при помощи приведения типа целого к указателю на структуру. Но инициализировать структуру по такому указателю я не могу. На строку с инициализацией компилятор (Keil Arm Compiler V5.06) ругается. #include <stdint.h> // Некая структура для примера struct MyConfig_st { uint8_t Field1; uint8_t Field2; uint8_t Field3; }; #define CONFIG_ADR 0x20000 // Адрес стр-ры конфигурации в памяти EEPROM #define MyConfig_ptr ((MyConfig_st*)CONFIG_ADR) // Указатель на стр-ру конфигурации в памяти EEPROM // Объявляем и инициализируем стр-ру в памяти EEPROM const MyConfig_st *MyConfig_ptr = {.Field1=0x66,.Field2=0x41,.Field3=0x7}; // Компилятор ругается !!! int main() { while(1); } Есть ли возможность сделать такое без использования директив размещения, которые в разных IDE и компиляторах/линкерах разные? Хотелось бы написать универсальный код, одинаково работающий везде, вне зависимости от среды разработки и компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 10 октября, 2018 Опубликовано 10 октября, 2018 · Жалоба На плюсах - написать конструктор для этой структуры и разместить ее через placement new(). На "голых" сях - написать функцию инициализации, в которую передавать указатель на структуру, т.е. то же самое, но "закат солнца вручную". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба 7 hours ago, Сергей Борщ said: На "голых" сях - написать функцию инициализации, в которую передавать указатель на структуру Что-то типа такого? #include <stdint.h> // Простая структура для примера struct MyConfig_st { uint8_t Field1; uint8_t Field2; uint8_t Field3; }; #define CONFIG_ADR 0x20000 // Адрес стр-ры конфигурации в памяти EEPROM #define MyConfig_ptr ((MyConfig_st*)CONFIG_ADR) // Указатель на стр-ру конфигурации в памяти EEPROM // Заполнение стр-ры значениями // S - указатель на стр-ру // F1, F2, F3 - значения полей void MyConfigInic (MyConfig_st* S,uint8_t F1,uint8_t F2,uint8_t F3) { S->Field1 = F1; S->Field2 = F2; S->Field3 = F3; } uint8_t tmp; // Сюда будем считывать данные из стр-ры int main () { // Присваиваем значение полям стр-ры MyConfigInic (MyConfig_ptr,0x66,0x41,0x7); // Считываем значения полей стр-ры tmp = MyConfig_ptr->Field1; // Прочитали значение 0x66 tmp = MyConfig_ptr->Field2; // Прочитали значение 0x41 tmp = MyConfig_ptr->Field3; // Прочитали значение 0x7 } Такое нормально сработает, если область размещения стр-ры будет в ОЗУ. При вызове функции MyConfigInic() с указателем на стр-ру и значениями для заполнения полей произойдёт присваивание полям стр-ры новых значений из аргументов ф-ции. Далее с полями стр-ры можно будет работать, обращаясь к ним через указатель. Но если стр-ра должна размещаться в области флеш-памяти, т.е. там же, где и код программы, то такой код не сможет инициализировать стр-ру данными. Простое присваивание данным во флеш-памяти новых значений не запишет там ничего. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
V_G 7 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба С какой стати голые Си, С++ должны знать структурную организацию памяти конкретного процессора/контроллера? Хотите работать с флэшью конкретного процессора, используйте специфические директивы конкретного IDE. Например,в Кейле для АРМ: uint32_t Dev __attribute__(at Addr) = 100; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба 5 часов назад, Darth Vader сказал: Но если стр-ра должна размещаться в области флеш-памяти На этот случай стандартного решения не существует. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 11 октября, 2018 Опубликовано 11 октября, 2018 · Жалоба 12 hours ago, V_G said: С какой стати голые Си, С++ должны знать структурную организацию памяти конкретного процессора/контроллера? Для описанной задачи этого не требуется. Всё, что надо для этого знать я сообщил компилятору двумя макросами: #define CONFIG_ADR 0x20000 // Адрес стр-ры конфигурации в памяти EEPROM #define MyConfig_ptr ((MyConfig_st*)CONFIG_ADR) // Указатель на стр-ру конфигурации в памяти EEPROM и описанием типа (структуры) MyConfig_st. От языка/компилятора требуется лишь поддержка инициализации объекта по указателю на него (тот самый (MyConfig_st*)CONFIG_ADR ). А с этим, как оказалось, засада. Указатель создать можно. Его можно использовать в коде для обращения к объектам: записи/чтения в/из них значений. На этом принципе построено обращение ко всем регистрам периферии. Но вот инициализировать объект по нему списком инициализации почему-то оказалось нельзя. По имени объекта можно, а по указателю на него нельзя. Было бы можно - задача решилась бы. 8 hours ago, Сергей Борщ said: На этот случай стандартного решения не существует. Жаль. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 14 октября, 2018 Опубликовано 14 октября, 2018 (изменено) · Жалоба Пришлось-таки использовать директивы. Чтобы скрыть компиляторозависимую часть кода - обернул её макросом. Пока что определил только часть для Кейла. Когда понадобится использовать код в других IDE с другими компиляторами - надо будет взамен #error определить соответствующие директивы размещения. #include <stdint.h> // Простая структура для примера struct MyConfig_st { uint8_t Field1; uint8_t Field2; uint8_t Field3; }; #define CONFIG_ADR 0x1E800 // Адрес структуры конфигурации в памяти EEPROM // Макрос атрибута размещения объекта по адресу ADR_VAL #if defined ( __CC_ARM ) // for ARM Compiler #define __AT_ADDR(ADR_VAL) __attribute__((at(ADR_VAL))) #elif defined ( __ICCARM__ ) // for IAR Compiler #error __AT_ADDR(ADR_VAL) не определён для компилятора IAR! #elif defined ( __GNUC__ ) // for GNU Compiler #error __AT_ADDR(ADR_VAL) не определён для компилятора GNU! #elif defined ( __TASKING__ ) // for TASKING Compiler #error __AT_ADDR(ADR_VAL) не определён для компилятора TASKING! #elif defined ( __CMCARM__ ) // for Phyton CMC-ARM Compiler #error __AT_ADDR(ADR_VAL) не определён для компилятора Phyton CMC-ARM! #else #error __AT_ADDR(ADR_VAL) не определён для используемого компилятора! #endif // Объявляем и инициализируем константную структуру конфигурации по адресу CONFIG_ADR const MyConfig_st MyConfig __AT_ADDR(CONFIG_ADR) ={0x66,0x41,0x7}; Изменено 14 октября, 2018 пользователем Darth Vader Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
firew0rker 0 15 октября, 2018 Опубликовано 15 октября, 2018 · Жалоба Чтобы сохранять переменную между ресетами, её недостаточно разместить в неинициализируемой секции, которую линкер найдёт где конкретно разместить в ОЗУ? Зачем задавать ей точный адрес? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
V_G 7 15 октября, 2018 Опубликовано 15 октября, 2018 · Жалоба 48 минут назад, firew0rker сказал: Чтобы сохранять переменную между ресетами, её недостаточно разместить в неинициализируемой секции, которую линкер найдёт где конкретно разместить в ОЗУ? Зачем задавать ей точный адрес? Если хочется иметь константу во флеше, и ее изредка модифицировать (настроечные операции), лучше знать адрес. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться