Program AVR EEPROM langsung dari sumber C.

11

Saat Anda memasukkan kode berikut dalam sumber AVR C, Anda dapat langsung memprogram sekering, tanpa perlu perintah tambahan atau file .hex:

#include <avr/io.h>

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

Apakah ada trik yang mirip dengan nilai-nilai program di EEPROM?

Saya telah memeriksa di /usr/lib/avr/include/avr/fuse.hmana saya dapat menemukan beberapa komentar tentang makro, tetapi saya tidak dapat menemukan komentar serupa di dalam /usr/lib/avr/include/avr/eeprom.hdan menafsirkan hal-hal preprosesor sedikit keluar dari liga saya.

Akan sangat berguna jika saya dapat memasukkan nilai EEPROM default dalam kode sumber C. Adakah yang tahu bagaimana mencapainya?

edit1:

Trik FUSES ini hanya dijalankan pada waktu ISP, bukan pada waktu RUN. Jadi tidak ada sekering yang diprogram dalam kode rakitan yang dihasilkan di controller. Alih-alih, programmer secara otomatis menggilir siklus pemrograman FUSES tambahan.

edit2:

Saya menggunakan avr-gcc dan avrdude toolchain di Linux.

jippie
sumber
Apakah ini hanya saat memprogram ISP? Sebagian besar bootloader tidak memungkinkan Anda memprogram sekering, bukan?
angelatlarge
2
Saya tidak punya waktu untuk menulis jawaban lengkap saat ini, tetapi sebagai petunjuk cobalah mencari di petunjuk EEMEM. Plus, Anda mungkin perlu mengubah pengaturan tautan untuk membuat file .EPP terpisah yang akan digunakan oleh programmer.
PeterJ
@angelatlarge Hanya pemrograman ISP. Tidak ada bootloader di pengaturan ini.
jippie
2
Perhatikan bahwa jawaban untuk ini sepenuhnya bergantung pada apa yang ingin dicatat oleh rantai alat dalam outputnya, dan apa yang ingin diprogram oleh programmer. Sebagian besar toolchains dapat dikonfigurasikan untuk membuat bagian khusus (atau meletakkan data pada alamat fiktif) sehingga pada akhirnya tergantung kepada programmer yang dapat mengekstraknya, atau dapat didorong oleh skrip khusus yang akan melakukannya.
Chris Stratton

Jawaban:

7

Dengan avr-gcc, EEMEMmakro dapat digunakan pada definisi variabel, lihat libcdokumen dan contoh di sini :

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

mendeklarasikan array karakter untuk berada di bagian bernama ".eeprom" yang setelah kompilasi memberitahu programmer bahwa data ini akan diprogram ke EEPROM. Bergantung pada perangkat lunak programmer Anda, Anda mungkin perlu secara eksplisit memberikan nama file ".eep" yang dibuat selama proses build ke programmer, atau mungkin secara implisit menemukannya dengan sendirinya.

JimmyB
sumber
Saya menggunakan nama file yang sedikit berbeda dari yang seharusnya, tetapi ini adalah perintah yang saya masukkan ke program EEPROM dari baris perintah (dan makefile):
jippie
1
Buat file yang berisi data Intel Hex yang digunakan oleh programmer:avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 ihex $(src).elf $(src).eeprom.hex
jippie
1
Pemrograman sebenarnya dilakukan oleh:avrdude -p$(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U eeprom:w:$(src).eeprom.hex
jippie
7

Ya, Anda dapat secara manual menulis data default ke EEPROM dalam kode sumber. Pertama, lihat panduan luar biasa ini pada EEPROM dengan AVR: Tutorial AVR EEPROM dari Dean. Juga, saya harus menambahkan bahwa itu adalah ide yang lebih baik untuk membuat file .eep yang berisi data EEPROM menggunakan makefile yang akan diprogram ke perangkat bersama dengan kode sumber. Namun, jika Anda tidak terbiasa dengan berbagai operasi makefile dan linker, itu masih dapat dilakukan dari dalam file kode sumber Anda - itu hanya akan terjadi segera setelah rangkaian diaktifkan, menghentikan operasi program awal.

Di awal program (sebelum loop utama), Anda dapat melakukan sesuatu seperti ini:

#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);

Fungsi "pembaruan" memeriksa terlebih dahulu untuk melihat apakah nilai itu sudah ada di sana, untuk menghemat penulisan yang tidak perlu, mempertahankan umur EEPROM. Namun, melakukan ini untuk lokasi yang sangat banyak dapat memakan waktu yang cukup lama. Mungkin lebih baik untuk memeriksa satu lokasi. Jika ini adalah nilai yang diinginkan, maka pembaruan lainnya dapat dilewati sepenuhnya. Sebagai contoh:

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);
}

Jika Anda ingin memperbarui data dalam jumlah besar, coba gunakan fungsi lain seperti eeprom_update_block(...). Dan pasti baca tutorial itu; itu ditulis dengan baik.

Anda bisa meletakkan semua pernyataan pembaruan EEPROM dalam satu pernyataan bersyarat preprocessor tunggal. Ini sangat mudah dilakukan:

#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_

Sedikit kode ini bahkan tidak akan dikompilasi kecuali jika Anda melakukan hal berikut:

#define _UPDATE_EEPROM_

Anda dapat meninggalkan ini di sana sebagai komentar, lalu batalkan komentar jika Anda perlu mengubah nilai EEPROM default. Untuk informasi lebih lanjut tentang preprosesor C, lihat manual online ini . Saya pikir Anda mungkin paling tertarik pada bagian tentang makro dan pernyataan kondisional.

Kurt E. Clothier
sumber
Sepertinya jawaban yang benar ada di paragraf terakhir dari PDF yang ditautkan. Ch. 7 Setting Initial Values.
jippie
Ya kamu benar. Saya menyebutkannya di paragraf pertama saya, tetapi melanjutkan jika Anda tidak terbiasa dengan file .eep dan linker di makefile!
Kurt E. Clothier
1
Menggunakan alamat EEPROM statis adalah praktik yang buruk. Lebih baik menggunakan atribut EEMEM sebagai gantinya dan membiarkan kompiler mengelola distribusi alamat. Juga, saya akan merekomendasikan untuk menerapkan / melakukan pemeriksaan CRC atas setiap bagian. Jika CRC gagal, bagian yang sesuai berisi data yang tidak diinisialisasi atau rusak. Dengan cara ini, Anda bahkan dapat menerapkan mekanisme fallback ke konfigurasi sebelumnya jika terjadi korupsi data.
Rev1.0
"Menggunakan alamat EEPROM statis adalah praktik yang buruk." Mengapa?
angelatlarge
1
Saat menggunakan EEMEMvariabel, kompiler menangani pengelolaan variabel mana yang berada di EEPROM. Dengan cara ini Anda hanya beroperasi pada pointer (konstan, yang dihasilkan kompiler) ke variabel saat mengakses data. Sebaliknya, jika Anda secara eksplisit menentukan alamat tempat masing-masing variabel berada, Anda harus mengurus sendiri alamat-alamat itu, termasuk memastikan bahwa tidak ada variabel yang secara tidak sengaja menempati alamat yang sama, saling menimpa; atau menghitung ulang semua alamat jika ukuran penyimpanan variabel berubah di masa depan dll.
JimmyB