Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Калибровочные таблицы во флеше
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
SpiritDance
Часто встает вопрос калибровки измерительных цепей. при этом устройство должно где-то запоминать полученные калибровочные коээфициэнты, чтобы калибровку не делать каждый раз заново.
eeprom в армах нет, есть только флеш, сооответсвенно устройство должно само записывать фо флеш и само считывать. Вопрос собственно заключается в том как грамотно это сделать на языке С, чтобы таблица не была жестко привязана к определенной странице памяти. Я просто выделяю отдельный сегмент для таких таблиц на асме и прикреплял его к определенному адресу. А как делаете ВЫ? Может есть более элегантный способ?
Alex03
Так вопрос про IAP или про помещение данных по адресам flash?

Какие проц и компиллер(да и среда)?
SpiritDance
Вопрос про размещение данных по адресам флеш. (Что такое IAP?... IAR?)
Процессоры lpc2000, sam7 и им подобные. Компилятор и конкретный проц (и тем более среда blink.gif ) вобщем-то значения не имеют в данном вопросе.
Alex03
Цитата(SpiritDance @ Oct 11 2006, 20:51) *
Вопрос про размещение данных по адресам флеш. (Что такое IAP?... IAR?)

В терминах филипса - In Application Programming

Цитата
Компилятор и конкретный проц (и тем более среда blink.gif ) вобщем-то значения не имеют в данном вопросе.

Если Вам надо на С, то ИМХО имеют.
Вариантов видимо много, например:
1. В лоб.
В проге используются жёстко заданные адреса, в настройке проекта (вот тут как раз среда и м.б. полезна, но конечно всё это линкеру скармливается) это некоторое адресное пространство "убрано" из доступной памяти.
Если переменная, структура одна - то подход ещё ничё, а если Вам их туда надо сотню то уже не очень. smile.gif

2. Использовать секции/сегменты, например для GCC
Код
int a __attribute__ ((section ("my_section")));
int b __attribute__ ((section ("my_section")));

Но опять же линкеру надо рассказать где какие секции/сегменты.
Timofey
Цитата
2. Использовать секции/сегменты, например для GCC
Код
int a __attribute__ ((section ("my_section")));
int b __attribute__ ((section ("my_section")));

Но опять же линкеру надо рассказать где какие секции/сегменты.
А для IARа 4.31 как указать? Я видел тут на форуме программу для записи во флэш, но чего то уж больно сложновато ..... Попроще нникак нельзя?
SpiritDance
Цитата(Timofey @ Oct 12 2006, 08:38) *
А для IARа 4.31 как указать?

Для IAR размещение можно указать с помощью pragma location
Код
#pragma location="MY_SECTION"
int a;
#pragma location="MY_SECTION"
int b;

ну и
Цитата
Но опять же линкеру надо рассказать где какие секции/сегменты.

smile.gif

Но меня отличия в реализации этого в компиляторах интересуют мало, это можно подсмотреть в документации. Я не совсем понимаю другое: как грамотно разместить эти сегменты и как потом презаписывать значения переменных? К тому же перезаписать можно как правило страницы памяти, а если структура меньше и остальные сегменты будут находится на той же страничке памяти? Равнять MY_SECTION по размеру страницы? Только по -моему линкер сам определяет конечный размер сегмента, а мы можем тоолько указать начальный адрес и максимальный размер. Или структуру равнять по размеру страницы? Вобщем вот собственно в чем вопрос-то.
Alex03
Цитата(SpiritDance @ Oct 12 2006, 12:00) *
Но меня отличия в реализации этого в компиляторах интересуют мало, это можно подсмотреть в документации. Я не совсем понимаю другое: как грамотно разместить эти сегменты и как потом презаписывать значения переменных? К тому же перезаписать можно как правило страницы памяти, а если структура меньше и остальные сегменты будут находится на той же страничке памяти? Равнять MY_SECTION по размеру страницы? Только по -моему линкер сам определяет конечный размер сегмента, а мы можем тоолько указать начальный адрес и максимальный размер. Или структуру равнять по размеру страницы? Вобщем вот собственно в чем вопрос-то.


Если памяти хватает то в отдельную страницу ИМХО лучше.
Если надо вместе с кодом/данными - то в поиске было про использование флеша вместо еепрома.
Мы везде Ramtron FRAM пользуем и не заморачиваемся.

По поводу размера сегмента и проч. в GCC есть linker script.
Например у меня CW генерит для GCC-ёвого линкера ld примерно такое файло:
Код
MEMORY
{
  UNPLACED_SECTIONS (wx) : ORIGIN = 0x100000000, LENGTH = 0
  AHB_Peripherals (wx) : ORIGIN = 0xffe00000, LENGTH = 0x00200000
  VPB_Peripherals (wx) : ORIGIN = 0xe0000000, LENGTH = 0x00200000
  BANK3 (wx) : ORIGIN = 0x83000000, LENGTH = 0x01000000
  BANK2 (wx) : ORIGIN = 0x82000000, LENGTH = 0x01000000
  BANK1 (wx) : ORIGIN = 0x81000000, LENGTH = 0x01000000
  BANK0 (wx) : ORIGIN = 0x80000000, LENGTH = 0x01000000
  SRAM (wx) : ORIGIN = 0x40000000, LENGTH = 0x00004000
  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
}


SECTIONS
{
  __AHB_Peripherals_segment_start__ = 0xffe00000;
  __AHB_Peripherals_segment_end__ = 0x00000000;
  __VPB_Peripherals_segment_start__ = 0xe0000000;
  __VPB_Peripherals_segment_end__ = 0xe0200000;
  __BANK3_segment_start__ = 0x83000000;
  __BANK3_segment_end__ = 0x84000000;
  __BANK2_segment_start__ = 0x82000000;
  __BANK2_segment_end__ = 0x83000000;
  __BANK1_segment_start__ = 0x81000000;
  __BANK1_segment_end__ = 0x82000000;
  __BANK0_segment_start__ = 0x80000000;
  __BANK0_segment_end__ = 0x81000000;
  __SRAM_segment_start__ = 0x40000000;
  __SRAM_segment_end__ = 0x40004000;
  __FLASH_segment_start__ = 0x00000000;
  __FLASH_segment_end__ = 0x00040000;

  __STACKSIZE__ = 1024;
  __STACKSIZE_IRQ__ = 256;
  __STACKSIZE_FIQ__ = 256;
  __STACKSIZE_SVC__ = 0;
  __STACKSIZE_ABT__ = 64;
  __STACKSIZE_UND__ = 0;
  __HEAPSIZE__ = 1024;

  __vectors_ram_load_start__ = __SRAM_segment_start__;
  .vectors_ram __SRAM_segment_start__ (NOLOAD) :
  {
    __vectors_ram_start__ = .;
    *(.vectors_ram)
    . = MAX(__vectors_ram_start__ + 0x3C , .);
  }
  __vectors_ram_end__ = __vectors_ram_start__ + SIZEOF(.vectors_ram);

  . = ASSERT(__vectors_ram_end__ >= __SRAM_segment_start__ && __vectors_ram_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .vectors_ram is too large to fit in SRAM memory segment");

  __vectors_load_start__ = __FLASH_segment_start__;
  .vectors __FLASH_segment_start__ :
  {
    __vectors_start__ = .;
    *(.vectors .vectors.*)
  }
  __vectors_end__ = __vectors_start__ + SIZEOF(.vectors);

  . = ASSERT(__vectors_end__ >= __FLASH_segment_start__ && __vectors_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .vectors is too large to fit in FLASH memory segment");

  __init_load_start__ = ALIGN(__vectors_end__ , 4);
  .init ALIGN(__vectors_end__ , 4) :
  {
    __init_start__ = .;
    *(.init .init.*)
  }
  __init_end__ = __init_start__ + SIZEOF(.init);

  . = ASSERT(__init_end__ >= __FLASH_segment_start__ && __init_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .init is too large to fit in FLASH memory segment");

  __text_load_start__ = ALIGN(__init_end__ , 4);
  .text ALIGN(__init_end__ , 4) :
  {
    __text_start__ = .;
    *(.text .text.* .glue_7t .glue_7 .gnu.linkonce.t.*)
  }
  __text_end__ = __text_start__ + SIZEOF(.text);

  . = ASSERT(__text_end__ >= __FLASH_segment_start__ && __text_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .text is too large to fit in FLASH memory segment");

  __dtors_load_start__ = ALIGN(__text_end__ , 4);
  .dtors ALIGN(__text_end__ , 4) :
  {
    __dtors_start__ = .;
    KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors))
  }
  __dtors_end__ = __dtors_start__ + SIZEOF(.dtors);

  . = ASSERT(__dtors_end__ >= __FLASH_segment_start__ && __dtors_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .dtors is too large to fit in FLASH memory segment");

  __ctors_load_start__ = ALIGN(__dtors_end__ , 4);
  .ctors ALIGN(__dtors_end__ , 4) :
  {
    __ctors_start__ = .;
    KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors))
  }
  __ctors_end__ = __ctors_start__ + SIZEOF(.ctors);

  . = ASSERT(__ctors_end__ >= __FLASH_segment_start__ && __ctors_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .ctors is too large to fit in FLASH memory segment");

  __rodata_load_start__ = ALIGN(__ctors_end__ , 4);
  .rodata ALIGN(__ctors_end__ , 4) :
  {
    __rodata_start__ = .;
    *(.rodata .rodata.* .gnu.linkonce.r.*)
  }
  __rodata_end__ = __rodata_start__ + SIZEOF(.rodata);

  . = ASSERT(__rodata_end__ >= __FLASH_segment_start__ && __rodata_end__ <= (__FLASH_segment_start__ + 0x00040000) , "error: .rodata is too large to fit in FLASH memory segment");

  __fast_load_start__ = ALIGN(__rodata_end__ , 4);
  .fast __vectors_ram_end__ : AT(ALIGN(__rodata_end__ , 4))
  {
    __fast_start__ = .;
    *(.fast .fast.*)
  }
  __fast_end__ = __fast_start__ + SIZEOF(.fast);

  __fast_load_end__ = __fast_load_start__ + SIZEOF(.fast);

  . = ASSERT((__fast_load_start__ + SIZEOF(.fast)) >= __FLASH_segment_start__ && (__fast_load_start__ + SIZEOF(.fast)) <= (__FLASH_segment_start__ + 0x00040000) , "error: .fast is too large to fit in FLASH memory segment");

  .fast_run ALIGN(__vectors_ram_end__ , 4) (NOLOAD) :
  {
    __fast_run_start__ = .;
    . = MAX(__fast_run_start__ + SIZEOF(.fast), .);
  }
  __fast_run_end__ = __fast_run_start__ + SIZEOF(.fast_run);

  . = ASSERT(__fast_run_end__ >= __SRAM_segment_start__ && __fast_run_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .fast_run is too large to fit in SRAM memory segment");

  __data_load_start__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4);
  .data __fast_run_end__ : AT(ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4))
  {
    __data_start__ = .;
    *(.data .data.* .gnu.linkonce.d.*)
  }
  __data_end__ = __data_start__ + SIZEOF(.data);

  __data_load_end__ = __data_load_start__ + SIZEOF(.data);

  __FLASH_segment_used_end__ = ALIGN(__fast_load_start__ + SIZEOF(.fast) , 4) + SIZEOF(.data);

  . = ASSERT((__data_load_start__ + SIZEOF(.data)) >= __FLASH_segment_start__ && (__data_load_start__ + SIZEOF(.data)) <= (__FLASH_segment_start__ + 0x00040000) , "error: .data is too large to fit in FLASH memory segment");

  .data_run ALIGN(__fast_run_end__ , 4) (NOLOAD) :
  {
    __data_run_start__ = .;
    . = MAX(__data_run_start__ + SIZEOF(.data), .);
  }
  __data_run_end__ = __data_run_start__ + SIZEOF(.data_run);

  . = ASSERT(__data_run_end__ >= __SRAM_segment_start__ && __data_run_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .data_run is too large to fit in SRAM memory segment");

  __bss_load_start__ = ALIGN(__data_run_end__ , 4);
  .bss ALIGN(__data_run_end__ , 4) (NOLOAD) :
  {
    __bss_start__ = .;
    *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON)
  }
  __bss_end__ = __bss_start__ + SIZEOF(.bss);

  . = ASSERT(__bss_end__ >= __SRAM_segment_start__ && __bss_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .bss is too large to fit in SRAM memory segment");

  __non_init_load_start__ = ALIGN(__bss_end__ , 4);
  .non_init ALIGN(__bss_end__ , 4) (NOLOAD) :
  {
    __non_init_start__ = .;
    *(.non_init .non_init.*)
  }
  __non_init_end__ = __non_init_start__ + SIZEOF(.non_init);

  . = ASSERT(__non_init_end__ >= __SRAM_segment_start__ && __non_init_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .non_init is too large to fit in SRAM memory segment");

  __heap_load_start__ = ALIGN(__non_init_end__ , 4);
  .heap ALIGN(__non_init_end__ , 4) (NOLOAD) :
  {
    __heap_start__ = .;
    *(.heap)
    . = MAX(__heap_start__ + __HEAPSIZE__ , .);
  }
  __heap_end__ = __heap_start__ + SIZEOF(.heap);

  . = ASSERT(__heap_end__ >= __SRAM_segment_start__ && __heap_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .heap is too large to fit in SRAM memory segment");

  __stack_load_start__ = ALIGN(__heap_end__ , 4);
  .stack ALIGN(__heap_end__ , 4) (NOLOAD) :
  {
    __stack_start__ = .;
    *(.stack)
    . = MAX(__stack_start__ + __STACKSIZE__ , .);
  }
  __stack_end__ = __stack_start__ + SIZEOF(.stack);

  . = ASSERT(__stack_end__ >= __SRAM_segment_start__ && __stack_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack is too large to fit in SRAM memory segment");

  __stack_irq_load_start__ = ALIGN(__stack_end__ , 4);
  .stack_irq ALIGN(__stack_end__ , 4) (NOLOAD) :
  {
    __stack_irq_start__ = .;
    *(.stack_irq)
    . = MAX(__stack_irq_start__ + __STACKSIZE_IRQ__ , .);
  }
  __stack_irq_end__ = __stack_irq_start__ + SIZEOF(.stack_irq);

  . = ASSERT(__stack_irq_end__ >= __SRAM_segment_start__ && __stack_irq_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack_irq is too large to fit in SRAM memory segment");

  __stack_fiq_load_start__ = ALIGN(__stack_irq_end__ , 4);
  .stack_fiq ALIGN(__stack_irq_end__ , 4) (NOLOAD) :
  {
    __stack_fiq_start__ = .;
    *(.stack_fiq)
    . = MAX(__stack_fiq_start__ + __STACKSIZE_FIQ__ , .);
  }
  __stack_fiq_end__ = __stack_fiq_start__ + SIZEOF(.stack_fiq);

  . = ASSERT(__stack_fiq_end__ >= __SRAM_segment_start__ && __stack_fiq_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack_fiq is too large to fit in SRAM memory segment");

  __stack_svc_load_start__ = ALIGN(__stack_fiq_end__ , 4);
  .stack_svc ALIGN(__stack_fiq_end__ , 4) (NOLOAD) :
  {
    __stack_svc_start__ = .;
    *(.stack_svc)
    . = MAX(__stack_svc_start__ + __STACKSIZE_SVC__ , .);
  }
  __stack_svc_end__ = __stack_svc_start__ + SIZEOF(.stack_svc);

  . = ASSERT(__stack_svc_end__ >= __SRAM_segment_start__ && __stack_svc_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack_svc is too large to fit in SRAM memory segment");

  __stack_abt_load_start__ = ALIGN(__stack_svc_end__ , 4);
  .stack_abt ALIGN(__stack_svc_end__ , 4) (NOLOAD) :
  {
    __stack_abt_start__ = .;
    *(.stack_abt)
    . = MAX(__stack_abt_start__ + __STACKSIZE_ABT__ , .);
  }
  __stack_abt_end__ = __stack_abt_start__ + SIZEOF(.stack_abt);

  . = ASSERT(__stack_abt_end__ >= __SRAM_segment_start__ && __stack_abt_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack_abt is too large to fit in SRAM memory segment");

  __stack_und_load_start__ = ALIGN(__stack_abt_end__ , 4);
  .stack_und ALIGN(__stack_abt_end__ , 4) (NOLOAD) :
  {
    __stack_und_start__ = .;
    *(.stack_und)
    . = MAX(__stack_und_start__ + __STACKSIZE_UND__ , .);
  }
  __stack_und_end__ = __stack_und_start__ + SIZEOF(.stack_und);

  __SRAM_segment_used_end__ = ALIGN(__stack_abt_end__ , 4) + SIZEOF(.stack_und);

  . = ASSERT(__stack_und_end__ >= __SRAM_segment_start__ && __stack_und_end__ <= (__SRAM_segment_start__ + 0x00004000) , "error: .stack_und is too large to fit in SRAM memory segment");

}
Kaplinsky
А если предложить держать например страницу в оперативке где будут эти константы хранится во время выполнения программы.А в конце работы или периодически эти константы будут записыватся во флеш.
При старте считывать из флеша и заполнять RAM.
Это к вопросу об записи флеша страницами.
Andy Mozzhevilov
Цитата(SpiritDance @ Oct 12 2006, 12:00) *
Но меня отличия в реализации этого в компиляторах интересуют мало, это можно подсмотреть в документации. Я не совсем понимаю другое: как грамотно разместить эти сегменты и как потом презаписывать значения переменных? К тому же перезаписать можно как правило страницы памяти, а если структура меньше и остальные сегменты будут находится на той же страничке памяти? Равнять MY_SECTION по размеру страницы? Только по -моему линкер сам определяет конечный размер сегмента, а мы можем тоолько указать начальный адрес и максимальный размер. Или структуру равнять по размеру страницы? Вобщем вот собственно в чем вопрос-то.


Линкеру можно указать, какие сегменты в какие адреса рассовывать. Компилятору можно указать,
в какие сегменты поместить переменные. Как - искать в документации на конкретный
компилятор/линкер. Это как раз не проблема.
Более важно решить такие вопросы:
Флэш в uC разбита на сектора. Стирание может происходить только сектора целиком.
Значит нужно выбрать сектор и выделить его под хранение интересующих значений.
Размеры секторов и их адреса не обязаны совпадать у контроллеров разных производителей,
это первая причина, по которой не получится полная независимость программы от конкретного камня.
Далее, запись во флэш в режиме выполнения программы (IAP - как говорили выше) - процесс
тем более зависящий от конкретного производителя семейства контроллеров, это вторая причина, по
которой универсальной программы для различных uC не получится.
То есть нужно:
1. Выбрать в контроллере страницу flash подходящего размера.
2. Исключить адреса этой страницы из линковки программы.
3. Отвести эту страницу для линковки сегментов, определенных для настроек в программе на Ц.
4. При необходимости можно проинитить эти переменные значениями по умолчанию.
5. Написать для каждого типа контроллера драйвер с универсальным API, который будет служить прослойкой между основной программой и механизмом IAP конкретного контроллера.

В зависимости от конкретных потребностей запись настроек может производиться как опеация
стирания старых и записи новых, или как дозапись новых в конец старых (пока не кончится сектор),
или можно выделить 2 сектора, и писать в них попеременно.
В вашем варианте, если я правильно понял, настроек мало, а сектор большой.
Тогда можно, например, объявить массив структур такой, чтобы этот размер равнялся размеру выбранного сектора или был чуть меньше.
Стуркутру делаете такую
struct one_item
{
unsigned char empty;
struct
{
...
} vars;
};

Потом делаете массив:

struct one_item all_items[100]; // 100 - это для примера

Поле empty будет играть роль флага отсутствия настроек в этом индексе массива.
Если это поле равно 0xff (значение стертой ячейки флэш), то все остальные поля настроек пусты.
Алгоритм при старте такой:
Проходитесь по массиву и ищите последнюю структуру, в которой empty != 0xff
Используете параметры vars.

Алгоритм при записи новых настроек такой:
Проходитесь по массиву и ищите первую структуру, в которой empty == 0xff
Записываете в нее новые значения vars и empty = 0.
Если все элементы массива заполнены, что стираете сектор и начинаете писать его заново.

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

Еще нужно обратить внимание, с блоками кокой длины работает IAP конкретного uC.
У LPC, насколько я помню, это 256 байт.

Хотите поговорить об этом ? smile.gif
vv95
Я выделял (для IAR msp430) сектора в xcl файле , типа
//Enable_Table ---- 0x1FF ------- 0.5 kByte --------------
-Z(CODE)Enable_Table=1100-12FF
получал адрес через
#define Adr_Enable_Table &arr_Enable_Table
#pragma memory=constseg(Enable_Table)
unsigned int arr_Enable_Table[0xFF] ={ .... }
#pragma memory=default
выделял памать RAM для блока (совместное использование с другими ф-ми)
писал ф-и типа запись байта:
CopyFlash_ToRAM(...) // чтение блока flash
M[x] = XX;
CopyRAM_ToFlash( ... )// запись блока flash
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.