Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WINAVR: pgmspace, eeprom
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
_Pasha
Предлагаю в этой ветке отражать передовые методы работы с pgmspace.h и eeprom.h
Может, потом закрепить тему. Тем более, что видны динамичные изменения в этой области.

Для начала. WINAVR-20071221 + Avr Studio 4.13 sp2 build 571

Делаю большой проект. Выложить не могу. Вкратце суть проблемы.
Использую хедер, в котором сведены вместе все параметры, хранящиеся в EEPROM
paramset.h
Код
#ifndef PARAMSET_H
#define PARAMSET_H 1
EEMEM uint16_t nominal_rpm = 500;
EEMEM uint8_t amplitude = 208;
................... etc
#endif


Хедер включается в разные модули. Их много. Везде константы из еепрома пользуются популярностью smile.gif
И, BTW, надо иметь на выходе файл *.eep для начальной заливки.

Для того, чтобы все работало, приходится объявлять параметры дважды - в основном модуле с инициализацией, а в остальных - как extern, т.е.
Код
#ifndef PARAMSET_H
#define PARAMSET_H 1
#ifdef _IN_MAIN_
EEMEM uint16_t nominal_rpm = 500;
EEMEM uint8_t amplitude = 208;
................... etc
#else
extern EEMEM uint16_t nominal_rpm;
extern EEMEM uint8_t amplitude;
................... etc
#endif

#endif


Потом, в основной программе
Код
#define _IN_MAIN_ 1
#include "paramset.h"


Иначе - чушь в распределении адресов.
Как избежать двойного объявления переменных в приведенном примере, ессно, без использования макросов?
Возможно ли это вообще?
Сергей Борщ
Цитата(_Pasha @ Apr 8 2008, 21:50) *
Как избежать двойного объявления переменных в приведенном примере, ессно, без использования макросов?
Возможно ли это вообще?
Объединить их в структуру:
Код
config.h:
#ifndef CONFIG_H__
#define CONFIG_H__
#include    <stdint.h>
#include    <avr/eeprom.h>

struct cfg_t
{
    uint16_t    Channel_Code;
    uint16_t    Tx_Period;
    uint8_t     Tx_Repeats;
    uint16_t    Cycle_Len;
    uint16_t    Cycle_Pos;
    uint8_t     Sec_TimeSlot;
}__attribute__((__packed__,__aligned__(1)));

extern EEMEM cfg_t Config_ee;
#endif  // CONFIG_H__

config.c:
#include    "config.h"

EEMEM cfg_t Config_ee =
{
   1,
   2,
   3,
   4,
};
singlskv
Цитата(Сергей Борщ @ Apr 8 2008, 23:16) *
Объединить их в структуру

+1
у меня примерно так же:
Код
typedef struct
{
  WORD  Resets;

  DWORD RUNTime;

  WORD  SysTickOverlapErrors;

  WORD  INTErrors;

  WORD  StackLeft;

  WORD  MinimumStackLeft;

  WORD  ADCErrors;

  WORD  EEPROMErrors;

  WORD  CRC16;

}TEEPROMStatisticBase;


TEEPROMBase EE[2] __attribute__ ((section (".eeprom")))=
{
  {       // первая копия
    0xAA,                  // Bad
    {
      1,                       // Resets
      0,                       // RUNTime
      0,                       // SysTickOverlapErrors
      0,                       // INTErrors
      STACK_SIZE,              // StackLeft
      STACK_SIZE,              // MinimumStackLeft
      0,                       // ADCErrors
      0,                       // EEPROMErrors
      0x7429,                  // CRC16
    },
.............................................
.............................................
_Pasha
Как автор темы позволю себе подытожить по этому примеру smile.gif

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

+ Структура позволяет решить проблему описаний и легко заливать defaults из флеша.
Если же последнее не предусмотрено, то
Макрос, который напрашивается здесь, имеет вид
Код
#define PARAM(_TYPE_ , _NAME_ , _INIT_) #ifdef _IN_MAIN_\
EEMEM _TYPE_ _NAME_ = _INIT_\
#else\
extern EEMEM _TYPE_ _NAME_\
#endif


НаписАл я эту довольно банальную вещь как раз для того, чтобы ее покритиковали.
ReAl
Цитата(_Pasha @ Apr 9 2008, 02:42) *
- Нечитабельность при инициализации достаточно большой структуры.
C99 позволяет
Код
typedef struct {
    uint8_t a;
    int b;
    char c;
} cfg_t;

// даже порядок инициализации не важен, всё будет правильно
cfg_t cfg EEMEM = {
  .b = -1 ,
  .c = '2' ,
  .a = 3
};

char arr[5] EEMEM = {
   [2] = 'c' ,
   [4] = 'e' ,
   [0] = 'a'  // элементы массива 1 и 3 инициализированы нулями по умолчанию
};
К сожалению, в С++ такого нет.

Цитата(_Pasha @ Apr 9 2008, 02:42) *
Макрос, который напрашивается здесь, имеет вид
Код
#define PARAM(_TYPE_ , _NAME_ , _INIT_) #ifdef _IN_MAIN_\
EEMEM _TYPE_ _NAME_ = _INIT_\
#else\
extern EEMEM _TYPE_ _NAME_\
#endif

Нельзя делать проверку условия внутри макроса. И нельзя всё одной строкой. Надо так:

Код
#ifdef _IN_MAIN_
#define PARAM(_TYPE_ , _NAME_ , _INIT_)  \
   EEMEM _TYPE_ _NAME_ = _INIT_
#else
#define PARAM(_TYPE_ , _NAME_ , _INIT_) extern EEMEM _TYPE_ _NAME_
#endif


Кстати, С99 позволяет это даже не при инициализации делать, можно делать эдакие "литералы"
Код
void foo(cfg_t *p)
{
    *p = (cfg_t){ .c = 'c', .b = -1, .a = 0 };
    // ну или     *p = (cfg_t){ 0, -1, 'c'};  для тех, кто помнит порядок полей;-)
}
вместо
Код
void foo(cfg_t *p)
{
    p->c = 'c';
    p->b = -1;
    p->a = 0;
}
И avr-gcc чудесно такое компилирует, я иногда пользуюсь.
А потом как вспомню, что далеко не все так стандарт поддерживают, как gcc, так и начинаю стараться не привыкать.

Ну и С++ такого не позволяет...
Даже с -std=gnu++98, не говоря уже о -std=c++98 --pedantic
amw
Цитата
Код
#ifndef PARAMSET_H
#define PARAMSET_H 1
EEMEM uint16_t nominal_rpm = 500;
EEMEM uint8_t amplitude = 208;
................... etc
#endif

А почему переменные объяляются в *.h файле?
Например config.h
Код
#ifndef PARAMSET_H
#define PARAMSET_H 1
extern EEMEM uint16_t nominal_rpm;
extern EEMEM uint8_t amplitude;
................... etc
#endif

config.c
Код
#include "config.h"
EEMEM uint16_t nominal_rpm = 500;
EEMEM uint8_t amplitude = 208;

А во всех остальных файлах просто
Код
#include "config.h"
_Pasha
Цитата(ReAl @ Apr 9 2008, 10:47) *
C99 позволяет
даже порядок инициализации не важен, всё будет правильно

А потом как вспомню, что далеко не все так стандарт поддерживают, как gcc, так и начинаю стараться не привыкать.


+1000
Потому что поддерживаемые в gcc операции с EEPROM тоже, мягко говоря, уникальны smile.gif
Так что с подводной лодки далеко не уплывешь... и можно и привыкнуть, ничего страшного.
mdmitry
Такой вариант:
В main все что надо, а в инклуде все extern. Этот инклуд в нужные файлы.
ReAl
Цитата(_Pasha @ Apr 9 2008, 17:38) *
+1000
Потому что поддерживаемые в gcc операции с EEPROM тоже, мягко говоря, уникальны smile.gif
Так что с подводной лодки далеко не уплывешь... и можно и привыкнуть, ничего страшного.
Увы, это разные вещи. Одно дело чисто gcc-шные расширения, типа диапазонных case в switch и вложенных функций. Приятные, но абсолютно нестандартные. Не так и жалко.
Другое дело - то, что с 1999 года в стандарте, уже скоро 10 лет, но от MS до IAR почти никто не поддерживает. Вот за это обидно. Вещи-то из СТАНДАРТА, а "виноват" потом окажется тот, кто этот стандарт поддержал.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.