Програмуйте AVR EEPROM безпосередньо з джерела С


11

Коли ви включаєте наступний код у джерело AVR C, ви, мабуть, можете безпосередньо програмувати запобіжники, не потребуючи додаткової команди або .hex-файлу:

#include <avr/io.h>

FUSES = {
        .low =          LFUSE_DEFAULT ,
        .high =         HFUSE_DEFAULT ,
        .extended =     EFUSE_DEFAULT ,
};

Чи існує схожа хитрість на програмні значення в EEPROM?

Я перевірив, /usr/lib/avr/include/avr/fuse.hде я можу знайти коментарі щодо макросу, але я не можу знайти подібний коментар у /usr/lib/avr/include/avr/eeprom.hта інтерпретації матеріалів препроцесора трохи не в моїй лізі.

Було б дуже зручно, якби я міг включити значення EEPROM за замовчуванням у вихідний код C. Хтось знає, як це досягти?

edit1:

Цей фокус FUSES виконується лише в ISP-час, а не в RUN-час. Таким чином, в отриманому коді збірки в контролері не запрограмовані запобіжники. Натомість програміст автоматично перемикає додатковий цикл програмування FUSES.

edit2:

Я використовую ланцюжок інструментів avr-gcc та avrdude в Linux.


Це лише при програмуванні ISP? Більшість завантажувачів не дозволяють програмувати запобіжники, правда?
angelatlarge

2
Я не маю часу написати повну відповідь на даний момент, але, як підказка, спробуйте пошукати директиву EEMEM. Крім того, вам може знадобитися змінити налаштування лінкера, щоб створити окремий .EPP-файл, який використовуватиме програміст.
PeterJ

@angelatlarge Тільки програмування ISP. У цій програмі завантажувача немає.
jippie

2
Зауважте, що відповіді на це повністю залежать від того, яку ланцюжок інструментів готовий записати у своєму випуску та що програміст готовий розібрати. Більшість ланцюжків інструментів можуть бути налаштовані для створення спеціального розділу (або розміщення даних за вигаданою адресою), тому в кінцевому підсумку це зводиться до того, що програміст може витягнути його, або бути спроможним керувати користувальницьким сценарієм, який би це зробив.
Кріс Страттон

Відповіді:


7

З avr-gcc EEMEMмакрос можна використовувати для визначення змінної, див. libcДокументи та приклад тут :

#include <avr/eeprom.h>
char myEepromString[] EEMEM = "Hello World!";

оголошує масив символів, який знаходиться у розділі ".eeprom", який після компіляції повідомляє програмісту, що ці дані потрібно запрограмувати в EEPROM. Залежно від програмного забезпечення, можливо, вам буде потрібно явно вказати програмісту назву ".eep" -файлу, створеного в процесі збирання, або він може неявно знайти його сам.


Я використовував трохи інше ім'я файлу, ніж я повинен був, але це команди, які я включив для програмування EEPROM з командного рядка (та makefile):
jippie

1
Створіть файл, що містить дані Intel Hex, використовувані програмістом:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
jippie

1
Фактичне програмування виконується:avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
jippie

7

Так, ви можете вручну записати дані за замовчуванням у EEPROM у вихідний код. По-перше, ознайомтеся з цим дивовижним посібником з EEPROM за допомогою AVR: Навчальний посібник Dean's AVR EEPROM. Крім того, слід додати, що кращою ідеєю є створення .eep-файлу, що містить дані EEPROM, використовуючи makefile, який буде запрограмований на пристрій разом із вихідним кодом. Однак якщо ви не знайомі з різними операціями makefile та linker, це все одно можна зробити з вашого файлу вихідного коду - це відбудеться, як тільки ланцюг живиться, зупиняючи початкову операцію програми.

На початку програми (перед будь-яким основним циклом) ви можете зробити щось подібне:

#include <avr/eeprom.h>

#define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_2 52  // This could be anything from 0 to the highest EEPROM address
#define ADDRESS_3 68  // This could be anything from 0 to the highest EEPROM address

uint8_t dataByte1 = 0x7F;  // Data for address 1
uint8_t dataByte2 = 0x33;  // Data for address 2
uint8_t dataByte3 = 0xCE;  // Data for address 3

eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);

Функція "update" спочатку перевіряє, чи є це значення вже, щоб зберегти на непотрібних записах, зберігаючи термін служби EEPROM. Однак це може зайняти зовсім небагато часу. Можливо, краще перевірити одне місце. Якщо це бажане значення, то решту оновлень можна пропустити повністю. Наприклад:

if(eeprom_read_byte((uint8_t*)SOME_LOCATION) != DESIRED_VALUE){
  eeprom_write_byte((uint8_t*)SOME_LOCATION, DESIRED_VALUE);
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
  eeprom_update_byte((uint8_t*)ADDRESS_2, dataByte2);
  eeprom_update_byte((uint8_t*)ADDRESS_3, dataByte3);
}

Якщо ви хочете оновити велику кількість даних, спробуйте скористатися іншими функціями, такими як eeprom_update_block(...). І обов'язково прочитайте цей підручник; це добре написано.

Ви можете помістити всі оператори оновлення EEPROM в один умовний оператор препроцесора. Це зробити дуже просто:

#if defined _UPDATE_EEPROM_
  #define ADDRESS_1 46  // This could be anything from 0 to the highest EEPROM address
  uint8_t dataByte = 0x7F;  // Data for address 1
  eeprom_update_byte((uint8_t*)ADDRESS_1, dataByte1);
#endif // _UPDATE_EEPROM_

Цей біт коду навіть не буде скомпільовано, якщо ви не зробите наступне:

#define _UPDATE_EEPROM_

Ви можете залишити це як коментар, а потім відмітити, якщо вам потрібно змінити значення EEPROM за замовчуванням. Для отримання додаткової інформації про препроцесор C, ознайомтеся з цим онлайн-посібником . Я думаю, що вас можуть найбільше зацікавити розділи про макроси та умовні заяви.


Схоже, правильна відповідь є в останньому абзаці пов'язаного PDF. Ch. 7 Setting Initial Values.
jippie

Так, ви праві. Я це згадував у своєму першому абзаці, але продовжувався, якщо ви не були знайомі з .eep-файлами та посиланням у makefile!
Курт Е. Клотьє

1
Використання статичних EEPROM-адрес - це погана практика. Краще замість цього використовувати атрибут EEMEM і дозволити компілятору керувати розподілом адреси. Крім того, я рекомендую здійснити / виконати перевірку CRC для кожного розділу. Якщо CRC не працює, відповідний розділ містить неініціалізовані або пошкоджені дані. Таким чином, ви навіть можете застосувати механізм резервного копіювання до попередньої конфігурації у випадку пошкодження даних.
Rev1.0

"Використання статичних EEPROM-адрес - це погана практика." Чому?
angelatlarge

1
Під час використання EEMEMзмінних компілятор дбає про керування змінною, яка знаходиться в EEPROM. Таким чином ви працюєте тільки на (постійні, створені компілятором) покажчики на змінні, коли отримуєте доступ до даних. Якщо, з іншого боку, ви чітко визначаєте адресу, де перебуває кожна змінна, вам доведеться самостійно дбати про ці адреси, включаючи переконання, що жодні змінні не займають однакову адресу, перезаписуючи одна одну; або повторний обчислення всіх адрес у разі зміни розміру пам’яті змінної у майбутньому тощо
JimmyB
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.