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

Привет, любители STM!

 

В последних версиях IAR уже почти нормально с модификатором __eeprom работает. Надо лишь реализовать три функции, которые в библиотеке не реализованы и на которые линкер ругается.

int __eeprom_wait_for_last_operation(void)
{
 if(FLASH_IAPSR_bit.WR_PG_DIS) return 0;
 while(!FLASH_IAPSR_bit.HVOFF);
 return 1;
}

void __eeprom_program_byte(uint8_t __near * dst, uint8_t v)
{
 *dst = v;
}

void __eeprom_program_long(uint8_t __near * dst, uint32_t v)
{
 FLASH_CR2_bit.WPRG = 1;
 *(dst++) = *((uint8_t*)(&v));   
 *(dst++) = *((uint8_t*)(&v) + 1);
 *(dst++) = *((uint8_t*)(&v) + 2);
 *dst = *((uint8_t*)(&v) + 3);  
}

Ну и не забывать разблокировать запись.

void EEPROM_Unlock(void)
{
 FLASH_DUKR = FLASH_RASS_KEY2;
 FLASH_DUKR = FLASH_RASS_KEY1;
}

void EEPROM_Lock(void)
{
 FLASH_IAPSR_bit.DUL=0;
}

 

А дальше как обычно определяем неинициализированные и инициализированные переменные с модификатором __eeprom и компилятор сам всё сделает.

__no_init __eeprom uint8_t x;
#pragma data_alignment=4
__no_init __eeprom uint32_t y;
__no_init __eeprom uint8_t z;
__eeprom uint8_t test[10]={ 1,2,3,4,5,6,7,8,9,10 };

int main()
{
 EEPROM_Unlock();
 x=test[5];
 z=x+1;
 y=0x12345678;
 EEPROM_Lock();
 for(;;);
}

 

И даже при отладке IAR сам прошивает инициализированные __eeprom переменные вместе с кодом. Удобно.

 

Следует обратить внимание на следующие вещи:

- почему-то компилятор смело при оптимизации выкидывает переменные с модификатором __eeprom. Мне кажется они должны быть по умолчанию volatile как и SFR, но нет. Ну нет, так нет. В приложенном проекте пришлось обтыкать их volatile.

- STM8 32-битные переменные шьёт за один присест, но для этого они должны быть выровнены по 4. Приходится компилятору напоминать о выравнивании.

- что-то мне с ходу не удалось получить два раздельных HEX с кодом и eeprom, но у меня опыт с STM8 аж один день :) Только сегодня STM8L-Discovery получил. Может кто научит?

 

Прикладываю проект для дискавери (STM8L152C6), может кому пригодится.

STM8_IAR_EEPROM.rar

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


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

Следует обратить внимание на следующие вещи:

- почему-то компилятор смело при оптимизации выкидывает переменные с модификатором __eeprom. Мне кажется они должны быть по умолчанию volatile как и SFR, но нет. Ну нет, так нет. В приложенном проекте пришлось обтыкать их volatile.

Выкидывает вероятно потому, что у Вас в коде к ним нет обращений? И выкидывает тогда не компилятор, а компоновщик (по этой причине). И правильно делает.

"Обтыкивать" в этом случае (если они нужны, но обращений почему-то нет) нужно не volatile, а добавлять префикс __root (см. доку на IAR).

Хотя - может подумать - почему переменная описана, а обращений к ней нет? Может что-то в консерватории структуре программы неправильно построено? :laughing:

 

PS: И почему у Вас инициализированные данные

__eeprom uint8_t test[10]={ 1,2,3,4,5,6,7,8,9,10 };

без модификатора const? Предполагается, что при каждом старте устройства, эти данные должны переписываться в EEPROM заново??? :wacko:

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


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

Выкидывает вероятно потому, что у Вас в коде к ним нет обращений?

Как это нет? main() смотрим внимательнее.

 

"Обтыкивать" в этом случае (если они нужны, но обращений почему-то нет) нужно не volatile, а добавлять префикс __root (см. доку на IAR).

Причём тут __root ? Обращения есть, модификатор __eeprom стоит, этого должно быть достаточно для запрета выкидывать операции с этими переменными.

 

 

PS: И почему у Вас инициализированные данные

__eeprom uint8_t test[10]={ 1,2,3,4,5,6,7,8,9,10 };

без модификатора const?

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

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

 

Предполагается, что при каждом старте устройства, эти данные должны переписываться в EEPROM заново??? :wacko:

Формально да, должен. Но если почитать докуентацию, то там будет следующее:

.eeprom.data

Description Holds static and global initialized and zero-initialized __eeprom variables. Eeprom

data is persistent, so this section should not be included in any initialize by copy

linker directive.

То есть, компилятор генерит сегмент данных для eeprom. Что с ним делать дальше решает пользователь.

При отладке в железке или симуляторе отладчик автоматически каждый раз загружает его в eeprom - тут всё чисто.

В случае релиза мы его прошиваем ручками один раз при программировании чипа. При следующих стартах гарантии что там будет прежнее значение нет. Формально - отступление от стандарта, а реально лишь особенность, привнесённая модификатором __eeprom. Это ни хорошо, ни плохо, а так есть и удобно!

 

 

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


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

Как это нет? main() смотрим внимательнее.

Причём тут __root ? Обращения есть, модификатор __eeprom стоит, этого должно быть достаточно для запрета выкидывать операции с этими переменными.

И что там в main()? Смотрим внимательнее. ;)

Какие-то присваивания, каких-то переменных, которые потом больше нигде не используются, не передаются ни в какие функции и не присваиваются никаким volatile переменным?

Вот это и называется "переменная не используется", по этой причине компилятор/линкер имеет полное право её выкинуть.

Компилятор всё сделал правильно, а Вам стоит повышать свой уровень в написании ПО ;)

 

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

Я Вам ничего не запрещаю, я просто читаю что у Вас там написано. А написано у Вас инструкция компилятору, что нужно разместить test в модифицируемой памяти и при старте ПО startup-код должен проинициализировать её указанным значением. Вот именно это компилятор и будет делать.

Возможно Вы именно этого и хотели. Но возможно что и нет, ибо это - одна из распространённых ошибок начинающих при описании инициализированных переменных в ОЗУ :laughing:

Здесь как бы неясно - возможно, что в IAR ключевое слово __eeprom включает в себя неявно и префикс const, но трудно сказать.

 

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

"неконстантная переменная" - это нонсенс. Может быть или переменная или константа. Тут как ни договаривайся - компилятор мзду не берёт :biggrin:

 

Формально да, должен. Но если почитать докуентацию, то там будет следующее:

Вполне возможно, что префикс __eeprom неявно включает в себя const. Но не факт.

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


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

Вот это и называется "переменная не используется", по этой причине компилятор/линкер имеет полное право её выкинуть.

Как это не используется? Она хранится в EEPROM после выключения питания! И компилятор об этом знает, я же ему об этом и указал посредством __eeprom. Я считаю это достаточным, разработчики компилятора нет. Это лишь условность, которая определена для модификатора __eeprom и я просто обратил на неё внимание, чтобы новички не попались.

 

А написано у Вас инструкция компилятору, что нужно разместить test в модифицируемой памяти и при старте ПО startup-код должен проинициализировать её указанным значением. Вот именно это компилятор и будет делать.

Нет, не будет. Будет делать то что написано в документации, а что там написано - смотрите предыдущий пост.

 

Возможно Вы именно этого и хотели. Но возможно что и нет,

Предлагаю подумать над вопросом почему у меня в примере инициализированные и неинициализированные переменные разной размерности и выравнивания применены.

 

ибо это - одна из распространённых ошибок начинающих при описании инициализированных переменных в ОЗУ :laughing:

Здесь как бы неясно - возможно, что в IAR ключевое слово __eeprom включает в себя неявно и префикс const, но трудно сказать.

Ошибка - делать умозаключение не прочитав документацию.

 

"неконстантная переменная" - это нонсенс. Может быть или переменная или константа. Тут как ни договаривайся - компилятор мзду не берёт :biggrin:

Или, сюрприз, "константная переменная". Под "неконстантной переменной" я, возможно коряво, имел в виду, что данная переменная не относится к классу "константных переменных". Ну да, получается, что этот массив обычная переменная, только с модификатором __eeprom, который намекает компилятору что с ней надо как-то по особенному работать.

 

Вполне возможно, что префикс __eeprom неявно включает в себя const. Но не факт.

А может почитать документацию, а не гадать?

 

jcxz, ну всё же, почему вы хотите EEPROM сделать const насильно? Он для того и придуман чтобы в него писать. Во так, например:

post-4140-1501504274_thumb.png

Хотелось бы посмотреть как вы будете писать в константную переменную и что вам на это компилятор скажет.

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


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

Тут как ни договаривайся - компилятор мзду не берёт :biggrin:

 

Ну это как предложить :) Следите за руками.

Размещаем переменную во FLASH. Хотите неинициализированную, хотите инициализированную, не важно.

И записываем в неё.

 

post-4140-1501510560_thumb.png

 

Упс! Компилятор даже не пискнул! Но это так, чисто поржать. :)

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


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

Как это не используется? Она хранится в EEPROM после выключения питания! И компилятор об этом знает, я же ему об этом и указал посредством __eeprom. Я считаю это достаточным, разработчики компилятора нет. Это лишь условность, которая определена для модификатора __eeprom и я просто обратил на неё внимание, чтобы новички не попались.

Попробуйте создать константу во флешь. И присвоить её значение какой-то переменной, которая потом не используется.

Корректный оптимизирующий компилятор её не поместит в выходной образ.

Шок! да?? Ведь если следовать Вашей логике как он мог её удалить - ведь оно там хранится (переменная в ОЗУ или константа во flash - не важно).

Странно почему это разработчики компиляторов считают по другому, не находите? Может надо пересмотреть своё видение мира?

И с __eeprom всё то же самое.

 

Ошибка - делать умозаключение не прочитав документацию.

Странные умозаключения Вы оттуда почерпнули. И то что они противоречат логике работы оптимизирующего компилятора, Вас похоже даже не насторожило - они все дураки, я один умный :biggrin:

 

Ну да, получается, что этот массив обычная переменная, только с модификатором __eeprom, который намекает компилятору что с ней надо как-то по особенному работать.

Вот, до Вас уже всё таки доходит истина! :rolleyes:

То, как Вы описали test - это именно переменная, а не константа. Наличие данных справа от неё говорит, что она инициализированная. А инициализацией переменных в си занимается стартап-код, который выполняется при старте ПО. Вот он и должен будет при старте устройства, записать в эту переменную указанное значение.

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

 

А может почитать документацию, а не гадать?

Документацию на что? На язык си? Да, пожалуй Вам стоит её почитать :laughing:

 

jcxz, ну всё же, почему вы хотите EEPROM сделать const насильно? Он для того и придуман чтобы в него писать. Во так, например:

Я ничего не хочу. Я всего лишь написал, что то как описан был Ваш массив, как бы намекает что там должно быть ключевое слово const скорей всего.

А если там реально нет этого слова, то я написал что будет делать компилятор в этом случае.

 

Хотелось бы посмотреть как вы будете писать в константную переменную и что вам на это компилятор скажет.

Такого бреда я делать не буду. Ибо "константная переменная" - это Ваше изобретение. Вы сами то разве не понимаете бредовость этого термина??? :wacko:

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


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

А если там реально нет этого слова, то я написал что будет делать компилятор в этом случае.

И попали пальцем в небо, потому что делать этого он не будет. Почему, читайте документацию на компилятор, я уже давал цитату.

 

Ибо "константная переменная" - это Ваше изобретение.

Рекомендую ознакомиться с трудами Бьёрна Страуструпа. Можете даже оспорить их, а я пасс, пожалуй, понаблюдаю со стороны.

 

PS: я тут файлик внизу оставлю, не вздумайте его читать!

24._Constant_varyables.pdf

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


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

2VladislavS

Предполагается, что при каждом старте устройства, эти данные должны переписываться в EEPROM заново??? :wacko:

вопрос остался. у меня тоже этот вопрос возник и не нашел(не придумал) на него ответ

 

 

и ещё вопрос.... на сколько модификатор __eeprom съедает меньше флеша, чем spl?

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


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

вопрос остался. у меня тоже этот вопрос возник и не нашел(не придумал) на него ответ

Товарищ противоречит сам себе, но даже этого не замечает. :rolleyes:

При описании переменных, которые не должны ничем инициализироваться (даже нулями) он объявляет переменную как:

__no_init __eeprom uint8_t z;

что уже как бы намекает, что если её объявить без __no_init, то стартап-код её должен обнулить (как для обычных RAM-переменных) записью в EEPROM,

но при этом объявляет массив с начальным значением в __eeprom и упорно твердит что он не будет переписываться в EEPROM при каждом рестарте устройства.

Значит - где-то обманывает :laughing:

 

и ещё вопрос.... на сколько модификатор __eeprom съедает меньше флеша, чем spl?

Ну так если:

__eeprom char const x[N] = {...};

то флеша ==0, только EEPROM.

А если:

__eeprom char x[N] = {...};

то как минимум N байт во флешь для хранения инициализационных данных {...} и ещё сколько-то байт на хранение процедуры записи EEPROM.

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


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

вопрос остался. у меня тоже этот вопрос возник и не нашел(не придумал) на него ответ

Инициализированные переменные с модификатором __eeprom не будут переписываться при каждом старте программы.

jcxz не слушайте, он неадекватен. Про сегменты EEPROM в документации IAR очень хорошо всё написано.

Смотрите, в конфигурационном файле линкера это всё отлично видно

/////////////////////////////////////////////////////////////////
//      Example ILINK command file for
//      STM8 IAR C/C++ Compiler and Assembler.
//
//      Copyright 2017 IAR Systems AB.
//
/////////////////////////////////////////////////////////////////

define memory with size = 16M;

define region TinyData = [from 0x00 to 0xFF];

define region NearData = [from 0x0000 to 0x07FF];

define region Eeprom = [from 0x1000 to 0x13FF];

define region BootROM = [from 0x6000 to 0x67FF];

define region NearFuncCode = [from 0x8000 to 0xFFFF];

define region FarFuncCode = [from 0x8000 to 0xFFFF];

define region HugeFuncCode = [from 0x8000 to 0xFFFF];


/////////////////////////////////////////////////////////////////

define block CSTACK with size = _CSTACK_SIZE  {};

define block HEAP  with size = _HEAP_SIZE {};

define block INTVEC with size = 0x80 { ro section .intvec };

// Initialization
initialize by copy { rw section .far.bss,
                    rw section .far.data,
                    rw section .far_func.textrw,
                    rw section .huge.bss,
                    rw section .huge.data,
                    rw section .huge_func.textrw,
                    rw section .iar.dynexit,
                    rw section .near.bss,
                    rw section .near.data,
                    rw section .near_func.textrw,
                    rw section .tiny.bss,
                    rw section .tiny.data,
                    ro section .tiny.rodata };

initialize by copy with packing = none {section __DLIB_PERTHREAD };

do not initialize  { rw section .eeprom.noinit,
                    rw section .far.noinit,
                    rw section .huge.noinit,
                    rw section .near.noinit,
                    rw section .tiny.noinit,
                    rw section .vregs };

// Placement
place at start of TinyData      { rw section .vregs };
place in TinyData               { rw section .tiny.bss,
                                 rw section .tiny.data,
                                 rw section .tiny.noinit,
                                 rw section .tiny.rodata };

place at end of NearData        { block CSTACK };
place in NearData               { block HEAP,
                                 rw section __DLIB_PERTHREAD,
                                 rw section .far.bss,
                                 rw section .far.data,
                                 rw section .far.noinit,
                                 rw section .far_func.textrw,
                                 rw section .huge.bss,
                                 rw section .huge.data,
                                 rw section .huge.noinit,
                                 rw section .huge_func.textrw,
                                 rw section .iar.dynexit,
                                 rw section .near.bss,
                                 rw section .near.data,
                                 rw section .near.noinit,
                                 rw section .near_func.textrw };

place at start of NearFuncCode  { block INTVEC };
place in NearFuncCode           { ro section __DLIB_PERTHREAD_init,
                                 ro section .far.data_init,
                                 ro section .far_func.textrw_init,
                                 ro section .huge.data_init,
                                 ro section .huge_func.textrw_init,
                                 ro section .iar.init_table,
               		  ro section .init_array,
                                 ro section .near.data_init,
                                 ro section .near.rodata,
			  ro section .near_func.text,
			  ro section .near_func.textrw_init,
                                 ro section .tiny.data_init,
                                 ro section .tiny.rodata_init };

place in FarFuncCode            { ro section .far.rodata,
                                 ro section .far_func.text };

place in HugeFuncCode           { ro section .huge.rodata,
                                 ro section .huge_func.text };

place in Eeprom                 {    section .eeprom.noinit };

place in Eeprom                 {    section .eeprom.data };

place in Eeprom                 {    section .eeprom.rodata };

/////////////////////////////////////////////////////////////////

 

и ещё вопрос.... на сколько модификатор __eeprom съедает меньше флеша, чем spl?

Библиотеки IAR для работы с EEPROM какие-то монстроидные. Прикладываю .map с моего примера. Вроде как 199 байт занимает.

st8test.zip

 

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


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

Смотрите, в конфигурационном файле линкера это всё отлично видно

Товарищ одыкватный, в какую из приведённых в Вашей портянке секций компоновщика попадает ваше творение строкой ниже ?:

__eeprom uint8_t test[10]={ 1,2,3,4,5,6,7,8,9,10 };

и почему?

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


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

Прекратите хамить собеседнику. При повторении будет предупреждение.

 

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


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

Инициализированные переменные с модификатором __eeprom попадут в секцию .eeprom.data и будут размещены линкером в региона Eeprom. И всё это согласно "IAR C/C++ Development Guide Compiling and Linking for the STMicroelectronics STM8 Microcontroller Family" страница 372.

 

Вместо того чтобы тут чушь нести уже давно бы прочитали документ. А ещё лучше скачали мой проект и посмотрели хотя бы в симуляторе как что инициализируется.

 

К сообщению приложил HEX с прошивкой, полученной из этого проекта. Найдите там во FLASH последовательность 1,2,3,4,5,6,7,8,9,10 которой по вашему при старте должен инициализироваться массив.

 

Страуструпа то переспорили?

 

stm8_eeprom.zip

 

 

 

 

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


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

Подтверждаю, никаких const писать не надо. Вот так вполне работает, ничего при старте не копируется.

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


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

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

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

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

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

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

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

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

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

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