Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запись структуры во флэш.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Jenya7
Я работаю с камнем EFM32TG842. У него есть сектор во флэше для записи данных пользователя - страница 512 байт. Я хочу записать туда свою структуру.
Код
struct sFlashParam
{
    uint16_t customerID;
    uint32_t mainCounter;        
    uint32_t CWcounter;
    uint8_t  mode;                
    uint8_t  channel;             
    uint8_t  meter_type;
       …и так далее.
}

и потом пишу.
Код
      
WriteToFlash(0x0FE00000, (uint32_t*)&flashParam1);

функция выглядит так
Код
void WriteToFlash(uint32_t address, uint32_t *data)
{
    uint32_t *addr = (uint32_t *) address;  //(uint32_t *)0x0FE00000;
    MSC_Init();
    MSC_ErasePage(addr);
    MSC_WriteWord(addr, data, sizeof(data));
    MSC_Deinit();
}

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


редактор
Скорее всего как в памяти отображается так и запишется. Со всеми "дырками" от выравнивания.
Считывать из флеша надо будет как точно такую же структуру.
ЗЫ:
Исключение - если функция записит знает, что пишет структуру, знает, какую структуру и будет разбирать ее по полям и записывать каждое поле отдельно. wink.gif Изврат, но реализуемо. Тогда функция чтения должна заниматься обратным процессом. Считывать отдельные поля и запихивать их в структуру.
Golikov A.
а вы запишите, считайте и узнаетеsm.gif

наверняка есть функция и ReadFromFlash
jcxz
Цитата(Jenya7 @ Nov 25 2014, 14:32) *
вопрос как структура запишется? каждый член структуры в 32-битный регистр?

Прежде чем брать в руки контроллер, нужно хотя-бы язык си выучить.
Тут уже не раз рекомендовали толковые книги для этого.

PS: В сад вобщем...
Jenya7
Цитата(Golikov A. @ Nov 25 2014, 15:18) *
а вы запишите, считайте и узнаетеsm.gif

наверняка есть функция и ReadFromFlash



функции записи-считывания я немного переделал и сейчас они выглядят так
Код
void WriteToFlash(uint32_t address, uint32_t *data, uint32_t size )
{
    uint32_t *addr = (uint32_t *) address;  
    MSC_Init();
    MSC_ErasePage(addr);
    MSC_WriteWord(addr, data, size);
    MSC_Deinit();

}

void ReadFromFlash(uint32_t offset, uint32_t *data, uint32_t size)
{
    int i;
    uint32_t *addr;
    for (i = 0; i < size; i++ )
    {
      addr = (uint32_t *)(offset  + i*4);
      data[i] = *addr;
    }
}


и тестирую (предварительно записав данные в структуру )
Код
WriteToFlash(0x0FE00000, (uint32_t*)&flashParam1, sizeof (struct sFlashParam1));

ReadFromFlash(0x0FE00000, (uint32_t*)&flashParam1, sizeof (struct sFlashParam1));


возвращает нули.
scifi
Цитата(Jenya7 @ Nov 25 2014, 12:38) *
Код
void ReadFromFlash(uint32_t offset, uint32_t *data, uint32_t size)
{
    int i;
    uint32_t *addr;
    for (i = 0; i < size; i++ )
    {
      addr = (uint32_t *)(offset  + i*4);
      data[i] = *addr;
    }
}

Под столом :-) А memcpy чем не угодил?
Вообще-то данные из флеш читаются точно так же, как из ОЗУ. Советую просто сделать указатель на структуру во флеш и читать через него:
Код
struct mystruct* const ptr = (struct mystruct*)0x12345678;

А ещё учите язык Си. Керниган и Ричи - хороший учебник.
Golikov A.
тут прикол в другом


uint32_t size
а при вызове человек передавал
sizeof(data)
а потом в цикле
i < size
addr = (uint32_t *)(offset + i*4);

то есть при передаче 1 32 битного слова, вы считаете 4 инта обратно....
круто!
mantech
Цитата(Jenya7 @ Nov 25 2014, 11:32) *
У него есть сектор во флэше для записи данных пользователя - страница 512 байт.


И что, прямо так и записывается, без всяких там разрешений записи во флеш, включения режимов записи, предварительного стирания сектора и т.п.?? Интересный камень, вернее, флешка у него интересная biggrin.gif

ЗЫ. Если не пишется структура, попробуйте записать просто массив чисел, и посмотреть, записался или нет...
Jenya7
Цитата(Golikov A. @ Nov 25 2014, 16:00) *
тут прикол в другом


uint32_t size
а при вызове человек передавал
sizeof(data)
а потом в цикле
i < size
addr = (uint32_t *)(offset + i*4);

то есть при передаче 1 32 битного слова, вы считаете 4 инта обратно....
круто!


дебагер показывает корректные адреса в цикле. приращение 4 байта.
Golikov A.
Цитата
И что, прямо так и записывается, без всяких там разрешений записи во флеш, включения режимов записи, предварительного стирания сектора и т.п.??

ну нет же... есть же
MSC_Init();
MSC_ErasePage(addr);

MSC_Deinit();


беспокоит
MSC_WriteWord(addr, data, sizeof(data)); - запись слова, странное имя функции, ну да ладно...


Цитата
дебагер показывает корректные адреса в цикле. приращение 4 байта.

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

пусть вам еще дебагер покажет такие вещи

Код
int32_t a;
sizeof(a);
int32_t TotalK = 0;

for(int i=0;i<sizeof(a);i++)
  TotalK = i*4;
Jenya7
Цитата(Golikov A. @ Nov 25 2014, 16:16) *
пусть вам еще дебагер покажет такие вещи

Код
int32_t a;
sizeof(a);
int32_t TotalK = 0;

for(int i=0;i<sizeof(a);i++)
  TotalK = i*4;


я наверное туплю, но я не вижу здесь криминала.
Golikov A.
sizeof - выдает длину в байтах.
и для инта_32 будет значение 4

и вместо одного слова вы считаете 4,
хотя возможно это не криминал в вашей разработкеwink.gif...
Jenya7
сделал по совету scifi .
Код
    
       memcpy(&flashParam1, 0x0FE00000, sizeof (struct sFlashParam1));


вроде как считывает корректные данные. значит и запись работает.
scifi
Цитата(Jenya7 @ Nov 25 2014, 14:22) *
Код
memcpy(&flashParam1, 0x0FE00000, sizeof (struct sFlashParam1));

Вы будете смеяться, но это то же самое, что и
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;
Jenya7
Цитата(scifi @ Nov 25 2014, 17:00) *
Вы будете смеяться, но это то же самое, что и
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;

да таки буду смеятся, какой я тупой. но я сегодня много чего выучил , благодаря вам добрым людям. sm.gif
Golikov A.
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;


А это по стандарту? Это как-то подменяется на memcpy неявно?
Jenya7
Цитата(Golikov A. @ Nov 25 2014, 17:39) *
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;


А это по стандарту? Это как-то подменяется на memcpy неявно?

у меня тоже такой вопрос возник. посмотрел в листинг но там ассемблер ничего не понятно.
Golikov A.
Мне как-то кажется такое присвоение не корректным, такого рода вещи решается не просмотром листинга а чтением стандарта. Но сейчас нет возможности, потому спросил, может кто из старших товарищей сразу знает ответ. Если не ответят позже надо будет почитать.
KnightIgor
Цитата(Jenya7 @ Nov 25 2014, 10:32) *
Я работаю с камнем EFM32TG842. У него есть сектор во флэше для записи данных пользователя - страница 512 байт. Я хочу записать туда свою структуру.

Код
void WriteToFlash(const uint32_t address, void const *data, uint32_t size)
{
    size = 4 * ((size + 3)/4); // always divisable by 4
    MSC_Init();
    MSC_ErasePage((const uint32_t *)address);
    MSC_WriteWord((const uint32_t *)address, data, size);
    MSC_Deinit();
}

Код
WriteToFlash(USERDATA_BASE, &my_struct, sizeof(my_struct));


Не забудьте также разместить функции работы с флэш в ОЗУ (требование процессора). В библиотеке уже все подготовлено, но в среде разработки в скаттер-файле надо указать разместить секцию ram_code в ОЗУ. Для KEIL это будет модификация подсекции загрузки ОЗУ:
Код
  RW_IRAM1 0x20000000 0x00004000  {; RW data
  *(ram_code, +First)             ; flash erase/write functions
   .ANY (+RW +ZI)
  }
Jenya7
Цитата(KnightIgor @ Nov 25 2014, 19:25) *
...


спасибо большое за ЦУ. а __attribute__ ((section(".ram"))) не поможет? вроде как это тоже указание на размещение функции в ram.
Golikov A.
получается копирование структур по указателю выдается на откуп компилятора. Если он умеет копировать каждое поле структуры, то он это может сделать. При этом указатели внутри буду скопированы по значению, то есть будут указывать на ту же область что в исходной структуре, и даже есть шанс что процедура копирования будет оптимизирована под конкретную архитектуру. То есть фактически полный аналог memcpy, интересно....
scifi
Цитата(Golikov A. @ Nov 25 2014, 15:39) *
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;

А это по стандарту? Это как-то подменяется на memcpy неявно?

В стандарте нет ничего, что это запрещало бы. С точностью до выравнивания, я думаю, но здесь адрес настолько ровный, что не важно. Ну и по крайней мере с одним компилятором видел, что туда тупо подставляется memcpy.
KnightIgor
Цитата(Jenya7 @ Nov 25 2014, 16:43) *
спасибо большое за ЦУ. а __attribute__ ((section(".ram"))) не поможет? вроде как это тоже указание на размещение функции в ram.

Функции работы с флэшем в библиотеке для EFM32 уже объявлены и "сложены" в именованную секцию "ram_code", поэтому нужно секцию "ram_code" лишь как-то поместить в ОЗУ. Как написано в помощи к функции WriteWord
Цитата
The flash must be erased prior to writing a new word. This function must be run from RAM. Failure to execute this portion of the code in RAM will result in a hardfault. For IAR, Rowley and Codesourcery this will be achieved automatically. For Keil uVision 4 you must define a section called "ram_code" and place this manually in your project's scatter file.

Кстати, коль мы о секциях заговорили.
Вы можете разместить структуру напрямую в пользовательской странице и работать с ней в коде программы как с нормальной константой во flash:
Код
const MyType MyStruct __attribute__((section("MYDATA"), used)) = {<init fields>};

В скаттере надо указать, чтобы все константы секции были размещены в пользовательской странице, то есть добавить load region
Код
LR_IROM_SETS   (0xFE00000) 0x200  {; User settings in the user    
  ER_IROM_SETS (0x0FE00000) 0x200  {; flash page
    *(MYDATA)
  }
}

В итоге, можно иметь константы, объявленные в разных участках кода, разных файлах проекта, но принадлежащие одной и той же именованной секции, как это показано выше, и пользовать их как обычные константы. А компоновщик кинет все в нужную область флэша согласно указанию из скаттера. Затем можно, например, через коммуникационный протокол модифицировать все эти константы, настраивая таким образом приложение. Например, сменить адрес узла, и т.п. И не надо хранить "копии" настроек из флэш в ОЗУ: в конце концов ОЗУ в контроллерах всегда существенно меньше, чем флэш.
Golikov A.
но как я понимаю главное в коде не забыться и не начать обращаться к переменным из флеша на запись? Можно конечно их все объявить константами, но тогда будет не очень удобно обновлять параметры из меню пользователя или через внешний протокол... если это только константы, то да удобно. Я во флэш пихал таблицы остатков при расчете crc16, очень удобно и они прям оттуда и брались при работе
KnightIgor
Цитата(Golikov A. @ Nov 25 2014, 19:58) *
Можно конечно их все объявить константами, но тогда будет не очень удобно обновлять параметры из меню пользователя или через внешний протокол... если это только константы, то да удобно.

Если параметры во флэше, - а я бы назвал это настройками, - обновляются не по 10 раз в секунду, а в какие-либо ключевые моменты жизни приложения, после чего последнее пользуется результатами и делает свою работу, то почему же не удобно обновлять прямо во флэше? Например, коэффициенты коррекций и поправок в системе с ADC, и т.п. Ну, вначале, при калибровке, может и надо будет раз 20 перезаписать настройки, но потом они будут довольно долго неизменны. Или вот пример из нашей практики. Надо управлять светодиодами через ШИМ. Характеристка вход-выход выражается степенной функцией (гамма-коррекция). Если считать на лету каждый раз по формуле для нескольких каналов, можно перегрузить процессор. Можно работать и по таблице, но ее надо качать по каналу. Мы же меняем показатель (гамму) короткой командой, а процессор тут же единожды вычисляет и создает таблицу, которой потом и пользуется постоянно. Все во флэше.
juvf
Цитата(scifi @ Nov 25 2014, 17:00) *
Вы будете смеяться, но это то же самое, что и
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;

это совершенно разные вещи.

так структуру объявлять не правильно, тем более для 32-х разрядного проца. Нужно выравнивать к 4-ём. Чтоб не париться над выравниванием лучше в структуре сначало объявить 32-х битные переменные ,потом 16-ти, затем 8-ми.
Golikov A.
да вот что-то получается что так наоборот даже более правильно чем через memcpy напрямую.

Цитата
то почему же не удобно обновлять прямо во флэше...

ну то есть у вас в коде это константы и вы их изменить не можете из программы. И есть дополнительные функции которые просто меняют область флеши, фактически не думая что там лежит и тем самым обходят защиту const.
В целом решение, проблему вижу только при изменении структуры настроек во время модификации кода, надо не забыть поправить ее в 2 местах. То есть и саму структуру и функции ее сохранения-модификации во флеше.
Jenya7
Цитата(juvf @ Nov 26 2014, 09:40) *
это совершенно разные вещи.

так структуру объявлять не правильно, тем более для 32-х разрядного проца. Нужно выравнивать к 4-ём. Чтоб не париться над выравниванием лучше в структуре сначало объявить 32-х битные переменные ,потом 16-ти, затем 8-ми.

как я понял если не указывать явно packed компайлер по дефолту делает padding.

Цитата(KnightIgor @ Nov 25 2014, 22:37) *
Функции работы с флэшем в библиотеке для EFM32 уже объявлены и "сложены" в именованную секцию "ram_code", поэтому нужно секцию "ram_code" лишь как-то поместить в ОЗУ. Как написано в помощи к функции WriteWord

Кстати, коль мы о секциях заговорили.
Вы можете разместить структуру напрямую в пользовательской странице и работать с ней в коде программы как с нормальной константой во flash:
Код
const MyType MyStruct __attribute__((section("MYDATA"), used)) = {<init fields>};

В скаттере надо указать, чтобы все константы секции были размещены в пользовательской странице, то есть добавить load region
Код
LR_IROM_SETS   (0xFE00000) 0x200  {; User settings in the user    
  ER_IROM_SETS (0x0FE00000) 0x200  {; flash page
    *(MYDATA)
  }
}

В итоге, можно иметь константы, объявленные в разных участках кода, разных файлах проекта, но принадлежащие одной и той же именованной секции, как это показано выше, и пользовать их как обычные константы. А компоновщик кинет все в нужную область флэша согласно указанию из скаттера. Затем можно, например, через коммуникационный протокол модифицировать все эти константы, настраивая таким образом приложение. Например, сменить адрес узла, и т.п. И не надо хранить "копии" настроек из флэш в ОЗУ: в конце концов ОЗУ в контроллерах всегда существенно меньше, чем флэш.


Я пишу в Attolic TrueStudio и я честно говоря не нашел там скаттер файл.
Сергей Борщ
Цитата(juvf @ Nov 26 2014, 06:40) *
так структуру объявлять не правильно
Это было не объявление структуры.
scifi
Цитата(Golikov A. @ Nov 26 2014, 09:26) *
ну то есть у вас в коде это константы и вы их изменить не можете из программы. И есть дополнительные функции которые просто меняют область флеши, фактически не думая что там лежит и тем самым обходят защиту const.

Если структура в флэш-памяти может меняться в процессе работы программы, её следует объявлять как const volatile.

Цитата(Golikov A. @ Nov 26 2014, 09:26) *
В целом решение, проблему вижу только при изменении структуры настроек во время модификации кода, надо не забыть поправить ее в 2 местах. То есть и саму структуру и функции ее сохранения-модификации во флеше.

Эта проблема - вовсе не проблема. Для этого существует X Macro.
Golikov A.
Прикольно, но все же не очень красиво. Дефайн передефайна здорово засоряет код. А потом опять же тяжело делать структуры с разными полями. В целом я понял, дефайнами можно выкрутиться, но читабельность имхо упадет
Velund
Конкретно для иара...

#pragma pack(1)

описание структуры

#pragma pack()


scifi
Цитата(Golikov A. @ Nov 26 2014, 11:33) *
Прикольно, но все же не очень красиво. Дефайн передефайна здорово засоряет код. А потом опять же тяжело делать структуры с разными полями. В целом я понял, дефайнами можно выкрутиться, но читабельность имхо упадет

На это ИМХО могу ответить фактами: ничего не падает, всё вполне красиво, работает отлично.
KnightIgor
Цитата(Jenya7 @ Nov 26 2014, 09:02) *
Я пишу в Attolic TrueStudio и я честно говоря не нашел там скаттер файл.

Однако способ управления размещением секций должен быть. Навскидку загуглил фразу "atollic truestudio linker script". Куча ссылок.
Golikov A.
Цитата
На это ИМХО могу ответить фактами: ничего не падает, всё вполне красиво, работает отлично.


а примерчик боевой можно? Не подкола ради, а чтобы поглядеть. Желательно для структурки и использование в разных функциях
scifi
Цитата(Golikov A. @ Nov 26 2014, 13:31) *
а примерчик боевой можно? Не подкола ради, а чтобы поглядеть. Желательно для структурки и использование в разных функциях

Почему бы и нет?
Golikov A.
спасибо, погляжу
Jenya7
Цитата(KnightIgor @ Nov 26 2014, 14:34) *
Однако способ управления размещением секций должен быть. Навскидку загуглил фразу "atollic truestudio linker script". Куча ссылок.

нашел файл efm32_flash.ld
CODE

/*
*****************************************************************************
**
** File : efm32_flash.ld
**
** Abstract : Linker script for EFM32TG842F32 Device with
** 32KByte FLASH, 4KByte RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : Energy Micro EFM32
**
** Environment : Atollic TrueSTUDIO®
**
** Distribution: The file is distributed “as is,” without any warranty
** of any kind.
**
** ©Copyright Atollic AB.
** You may use this file as-is or modify it according to the needs of your
** project. This file may only be built (assembled or compiled and linked)
** using the Atollic TrueSTUDIO® product. The use of this file together
** with other tools than Atollic TrueSTUDIO® is not permitted.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20001000; /* end of 4K RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x80; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 32K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 4K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}

/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH

/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)

KEEP (*(.init))
KEEP (*(.fini))

. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH

/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH

.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH

.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH

/* used by the startup to initialize data */
_sidata = LOADADDR(.data);

/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */

. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH

/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)

. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM

/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM

/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1

/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}

.ARM.attributes 0 : { *(.ARM.attributes) }
}



только не знаю куда там вставлять. я как вы поняли не такой спец. sm.gif
KnightIgor
Цитата(Jenya7 @ Nov 26 2014, 15:32) *
нашел файл efm32_flash.ld

Я не спец по GCC. По аналогии с KEIL мне кажется, что надо так-то так:

Код
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
*(ram_code)  /* <--------------------- */

. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM

Хотя еще раз напомню цитату из помощи к EFM32 библиотеке, что, возможно, уже все делается автоматически. Посмотрите карту памяти и поищите ram_code по тексту.
AHTOXA
Нет, RAM-функции надо не в bss (это неинициализированные данные), а в data (инициализированные данные).
(Потому что стартап-код bss просто заполняет нулями, а в data копирует их копию из флеша.
Как-то так:
Код
    .data :
    {
        . = ALIGN(4);
        _sdata = .;                /* start of .data label (in RAM, VMA) */
        *(.data)
        *(.data.*)
        *(.ram_code.*)  /* <--------------------- */
    } > RAM AT > FLASH
Aaron
Цитата(Golikov A. @ Nov 25 2014, 15:39) *
Код
flashParam1 = *(struct sFlashParam1*)0x0FE00000;


А это по стандарту? Это как-то подменяется на memcpy неявно?


Это, товарищи, мы с вами бородатые стали слишком sm.gif
Недавно тоже столкнулся с таким кодом - человек структуру просто приравнял к другой структуре. Я сказал ему исправить, но как ни странно, код оказался рабочим. Перечитывать пришлось стандарты языка C sm.gif
Вроде как копирование структур через оператор '=' в std=c99 появилось. Удобная штука! =)
KnightIgor
Цитата(Aaron @ Nov 28 2014, 09:57) *
Это, товарищи, мы с вами бородатые стали слишком sm.gif
Недавно тоже столкнулся с таким кодом - человек структуру просто приравнял к другой структуре. Я сказал ему исправить, но как ни странно, код оказался рабочим. Перечитывать пришлось стандарты языка C sm.gif
Вроде как копирование структур через оператор '=' в std=c99 появилось. Удобная штука! =)

А если глянуть в ассемблер, то при таком копировании используется memcpy(). Кстати, о C99. Он позволяет объявлять локальные массивы переменной длины внутри функции, в зависимости, скажем, от входного параметра:
Код
void func(size_t size)
{
   char buffer[size];
   ...
}

Под KEIL для этого используется malloc(). Так что нужно позаботиться о размере heap и полезно проверять: if (buffer) {...}. Правда, что делать, если buffer будет NULL, тоже не ясно. Hard Fault генерировать?
Вообще, жаль, что malloc(), а не типа SP -= size. Интересно, как делает GCC?
Сергей Борщ
Цитата(KnightIgor @ Nov 28 2014, 10:18) *
А если глянуть в ассемблер, то при таком копировании используется memcpy().
Может использоваться. А может не использоваться. А может не использоваться даже там, где явно вызывается в исходнике. Зависит от степени продвинутости компилятора. Например, если затраты на вызов memcpy() окажутся больше, чем прямое копирование через регистры. Если компилятор знает, что скопировать нужно 4 байта - проще и быстрее их перекидать через регистры.
Цитата(KnightIgor @ Nov 28 2014, 10:18) *
Под KEIL для этого используется malloc().
Хм. забавно. Стандарт говорит (6.2.4) , что такой массив должен иметь automatic storage duration, в то время как созданные через malloc() объекты имеют allocated storage duration. С другой стороны, если компилятор сам в нужных местах вызывает malloc() и free() для такого объекта - вроде бы и требования для automatic storage duration выполняются. То есть решение неожиданное, но тем не менее не запрещенное. gcc размещает такой массив на стеке.
Golikov A.
ну да на стэке как то логичнее... Он же локальный...

а про присвоение структур я почитал что это даже лучше чем memcpy, потому что в зависимости от доступных методов компилятор может сделать это наилучшим образом, то есть действительно имеет право выбирать способ копирования в зависимости заданной оптимизации, архитектуры и так далее...
KnightIgor
Цитата(Сергей Борщ @ Nov 28 2014, 11:53) *
gcc размещает такой массив на стеке.

Замечательно. Интересно, как убедить Keil делать так же...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.