Dahili EEPROM'u Ne Şekilde Kullanıyorsunuz?

Başlatan Tagli, 06 Şubat 2022, 21:42:37

Tagli

Dahili EEPROM'un istediğimiz adresine istediğimiz byte'ı yazabiliyoruz. Burada bir sorun yok. Ancak düşünülmesi gereken 2 gereksinim var, ve sizlerin bu gereksinimlere olan yaklaşımınızı merak ediyorum.

1. Yazma sırasında enerji kesilmesi veya reset durumunda eski değerin bozulmasını nasıl engelleriz?
2. EEPROM ömrünün tüm hücrelere eşit dağılmasını nasıl sağlarız? (wear leveling)

Bu iki gereksinimin nasıl karşılanacağı, EEPROM'un ne şekilde kullanılacağına da bağlı. İncelemeyi basitleştirmek için, 32-bitlik n sayıda değeri EEPROM'da saklamak istediğimizi düşünelim.

Sıfır Koruma, Bağımsız Yazım: En ilkel ve yukarıdaki 2 gereksinimi de karşılamayan yönteme de referans olması açısından değinelim. Bu yöntemde her değişkenin EEPROM'da sabit bir adresi var. Atıyorum a 0x00'da ise b 0x04'te. Ancak mesela a 1000 kez yazılırken b 1 kez yazılıyorsa, 0x00-0x03 adres aralığı daha hızlı aşınıyor. Ayrıca 4 byte'lık a değerinin mesela 2. byte'ını yazarken işlemci reset yerse, a değeri bozulmuş oluyor ve bunu anlamamızın veya eski değeri geri getirmemizin bir yolu da yok.

Çift koruma, Toplu Yazım: EEPROM konusunu internette araştırınca genelde bu ve benzeri yöntemlere denk geldim. Burada bir örneği var. Eğer n adet değişkenin hepsi toplu olarak güncellenecekse, mesela [a,b,c,d] dörtlüsü, ve bunlardan herhangi birini tek başına değiştirmek gerekmiyorsa en iyi yöntem bu. Hem EEPROM ömrünü uzatıyor, hem de yazma anında bir bozulma olursa eski değer sağlam kalıyor. Ama sadece b'yi değiştirmek istersem bile tüm [a,b,c,d] dörtlüsünü tekrar EEPROM'a yazmam gerekiyor.

Sadece Hata Koruması, Bağımsız Yazım: Eğer EEPROM ömrünün dengesiz tükenmesini dert etmiyorsanız ve sadece yazma anında enerji gitmesi veya reset'e karşı koruma gerekiyorsa durum basit bir algoritma ile çözülebilir gibi gözüküyor. İnternette bundan bahseden bir yazıya denk gelmedim, sadece kendim üzerinde biraz düşündüm.

Çift Koruma, Bağımsız Yazım: En zoru bu. Muhtemelen hafızayı bloklara bölüp, her birinin toplamda kaç kez yazılıp silindiğini de ayrıca saklamak gerekecek. Yeni bir değer yazılırken de en az kullanılmış blok tercih edilecek. Bunun üzerinde de biraz düşündüm, ancak henüz kodlamaya geçmedim. İnternette pek bahsedildiğini de görmedim. Benzer amaçlı olarak flash bellek üzerinde uygulamalar var gibi, ki kendim de yaptım böyle bir şey. Ancak EEPROM'a uygun bir şeye denk gelmedim.

Siz projelerinizde EEPROM'u ne şekilde kullanıyorsunuz?
Gökçe Tağlıoğlu

Erol YILMAZ

1. Enerji gittigine dair hizli bi sinyal hw olarak mcu ya ulasacak sekilde hazirdir.

2. Enerji gelince  eeprom icerigini RAM E aliriz. Program calistikca RAM'i guncelleriz.
Milyon defa guncelleriz. Sıkıntı yok.

3. Enerji giderken de RAM i  EEPROMa 1 kere kaydederiz.

Tagli

#2
Hocam peki enerji gitmesi harici durumlarda konfigürasyon vs. kaydetmek gerekmiyor mu? Burada bir wear leveling yöntemi uyguluyor musunuz? Ya da enerji gitmesi haricinde kayıt sırasında reset gelme ihtimali olabilir mi?

Kafama takılan bir şey daha var: Enerji gitmesi kabaca ne kadar zaman öncesinde tespit edilebiliyor? Yani mesela sinyal geldikten sonra kayıt için kaç ms süre var?
Gökçe Tağlıoğlu

Erol YILMAZ

Enerji gitmesi haricinde  bootloader talebi gelirse  reset lazim olabilir.
Onun haricinde enerji varken, mcu kontrolden cikip reset atiyorsa ciddi bir problem var demektir.
Bu yontemle Wear leveling'e ihtiyac kalmadi.

Regulatorun onune koyacagimiz CAP sureyi belirler. 500 mS dayansin kafi gelir sanirim.

erdcan

Dümdüz kullanıyormuşuz eeprom'u teşekkürler bilgilendirme için.

kantirici

#5
Merhaba,

Öncelikle veri bütünlüğünün kontrol edilmesi önemli. Bunun için yaygın yöntemler bcc, checksum, crc yada hash, md5 vb bir algoritma kullanmak. Bu yöntem ile verinin bozulup bozulmadığını anlayabiliriz. Ben çoğu durumda 32 bit crc kullanıyorum. Veri boyutu büyüdükçe ve güvenlik yüksek tutulmak isteniyorsa kullanılan algoritmanın kompleksliğini arttırmak gerekiyor. Ama çoğu durumda crc yeterli.

Verinin bozulması ihtimaline karşın bu veri bloğunun çoklu kayıt edilmesi gerekiyor. Bu durumda basit bir şekilde "recovery" yapabileceğiz. Bu gerekli hafıza alanını iki katına çıkartacaktır fakat çok önemli bir önlem.
Yazım sırasında kesinti olursa en fazla kopyalardan biri bozulacak, bu durumda hep son durum geri getirilecek.
Bunlar bilinen yöntemler ama tek başlarına yeterli değiller.

Öncelikle programın çalışması sırasında aslında her zaman hafızayı güncellemek gerekmiyor. @Erol YILMAZ beyin de belirttiği gibi periyodik olarak, önemli bir olay meydana geldiğinde gibi durumlarda ve elektrik kesintilerinde güncellemek yeterli oluyor. Bunun için en kötü ihtimalle güç kesildikten sonra yazım işleminin bitmesi kadar gereken enerjini kapasite/süper kapasiteden karşılanması gerek.

Ayrıca yazım bittikten sonra doğrulama yapmakta önemli.

Özellikle flash tabanlı bir hafıza kullanıyorsak bunlar zaten block tabanlı elemanlar. Yani istesekte 1 byte güncelleme yapamıyoruz. Block sil yaz yapmak gerkiyor. Bu noktada sizinde bahsettiğiniz "wear leveling" devreye giriyor. Bunu kendimiz yapmak istersek, baştan bir dosya sistemi yazmaya gidiyor iş. Çünkü oda olsun, bunada ihtiyaç olur vs derken iş oraya varıyor. Bu noktada karşımıza open soruce imdada yetişiyor. ARM geliştirdiği littlefs ve esp serilerinde vs çok kullanılan spiffs oldukça iyilier.

Spi flash'larda hücre ömrü genelde 100.000 bin yazım veriliyor. Ama tipik eepromlar 1.00.000 yazım. Mesela 24AA65 bu üründe bazı bölgöler 10.000.000 yazım verilmiş. Yani Eepromlarda zaten hücrenin aşınması genel ihtiyaçlar için sıkıntı yaratmamalı. Bundan dolayı flash tabanlı hafızalar genelde hücre aşınma destekli dosya sistemleri ile kullanılıyorken eeprom'lar standart kullanım gib düşünebiliriz.

Tagli

#6
Flash belleklerde şartlar daha farklı. Bunlar ile ilgili olarak etiket-değer (key-value) mantığı ile çalışan bir sistem oluşturdum. Normal dosya sistemi gibi değil, çok daha basit. Her kayıt için bir numara oluyor, belki bir çeşit dosya ismi gibi düşünülebilir. Şuna benzer fonksiyonları çağırabiliyorum:

void flashrec_mount(void);
rec_size_t flashrec_write(rec_key_t key, const void* source, rec_size_t size);
rec_size_t flashrec_read(rec_key_t key, void* target, size_t maxSize);
rec_size_t flashrec_size(rec_key_t key);
size_t flashrec_memUsed(void);
size_t flashrec_memTotal(void);

Yani mesela "1 numaraya 15 byte kayıt edeceğim" gibi. Daha sonra 1 numaraya 20 byte da kaydedebilirim, veya tamamen bu kaydı silebilirim. Ancak arkasına ekleme özelliği (append) yok.

Flash bellek EEPROM'a göre daha geniş, mesela birkaç kB alan ayırabiliyorum. Bunu da iki parçaya bölüyorum. Kayıtların eski versiyonları bellekte kalmaya devam ediyor ancak kayıt sırasına bakarak hangisinin eski hangisinin yeni olduğu belli oluyor. İlk yarı dolduğu zaman, sadece en güncel kayıtları ikinci yarıya taşıyıp ilk yarıyı bir bütün olarak siliyorum. Bu şekilde sıralı bir kullanımda bellek aşınması da düzenli oluyor. Elbette veri bütünlüğünü sağlayacak ek güvenlik önlemlerim de var.

EEPROM'da ise, mesela 8-bit PIC'ler için düşünürsek, toplamda 1 kB'tan az yer var. Son modelleri bilmiyorum ama eskiden kullanmaya alıştığım modellerde 256 byte gibi boyutlar yaygın. Ancak bütün halinde silme yapmadan, byte bazında veri güncellemek mümkün. Bir diğer avantajı da, yazma işlemi sırasında kodun devam edebiliyor oluşu. Halbuki flash'a yazma yaparken çoğu işlemci yazma işlemi boyunca kilitlenir (Kodu RAM'den çalıştırma gibi bir şey yapılmadıysa, veya flash dual bank değilse).

Bu konuyu açmaktaki amacım, EEPROM'un flash'tan farklı olan avantaj ve dezavantajlarını en iyi şekilde nasıl değerlendirebileceğimi anlamak idi.
Gökçe Tağlıoğlu

ziyaretci

#7
Enerji kesintisi sinyaline bakarak yazma işleminde:

-Trafodan AC röle sürülür.
-Kontak uçlarından kesme sinyali beklenir.

Ya da

-AC sinyali dijital seviyede frekansa dönüştürecek devre hazırlanır.
-Frekans sıfır olursa kesme sinyali oluşturulur.

Not: Şebekedeki gerilim düşüklüğü ikinci yöntemi sekteye uğratabilir. Çözümü var elbet ama amaç minimum malzeme ile hedefe ulaşmak. İlk yöntem güzeldir. Tabi örneğin genelde 12V'luk rölelerin minimum kontak çekme gerilimi 8V oluyor. Rölelerin bu minimum çalışma değeri göz önüne alınarak röle gerilimini minimum değere yaklaştıracak uygun seri direnç atılmalı.

Burada dikkat edilmesi gereken 6 husus var.

Bunlar;
1-Denetleyici beslemesine bağlı aşırı akım çeken bir yük olmayacak.

2-Yazılacak toplu verinin boyutuna bağlı olarak yazma süresi bilinecek.

3-Denetleyicinin nominal akımı bilinecek.

4-Denetleyici beslemesine paralel, yazma süresi için brownout reset eşiğine kadar enerji sağlayacak kapasite hesaplanacak.

5-Şebekedeki anlık kopmalara karşı kesme sinyalini gerçekçi kılacak kesinti algoritması eklenecek.

6-Bilgileri yazar yazmaz eğer vakit kaldıysa sistem boş sonsuz döngüye sokulacak.



Dipnot:
Elbette hiç bir yöntem mükemmel değildir. Her zaman getirdiğimiz mükemmel çözümün bile patlama olasılığı vardır. Bu nedenle yaptığım son projelerde enerji kesintisi için donanımsal bir giriş her zaman vardır fakat opsiyonel olarak bekletirim.
Eğer yanlış veri yazımı kullanıcıyı fazla yormayacak şekilde ise "sistemi fabrika ayarlarına sıfırla" seçeneği daha cazip geliyor. Kullanıcı en fazla parametreleri yeniden tanımlayacak.

Ama yapılan işin büyüklüğüne ve beklentilere göre bu durum değişir. Önemli olan, sistemi kilitleyecek bir açık unutmamaktır. Bundan sonraki önemli olan şey ise basit bir telefon görüşmesi  ile sistemi yeniden çalışır hale getirecek yönergeleri aktarabileceğimiz, iş kesintisini minumun süreye indirgeyen, kendini yeniden boot edebilecek bir sistem tasarlamaktır.

Patronlara son not: ( :P )
Geri bildirim(feedback) gelişimin yapı taşıdır. Gelişim ise her zaman bir süreçtir. Bu sürecin sonu ise kalitedir.

Düzeltme:
@Tagli hocamızın gerçekte bahsetmek istediği konuya ek olarak bunlar yazılmıştır.


muhendisbey

Eğer bir mcu içerisindeki eepromun ömründen şüphe duyuyorsak hatalı bir tasarım yaptığımızı kabul etmemiz gerekir. Çünkü mcu içerisindeki eepromun bir bilgisayar HDD'si gibi yaz-sil belleği gibi düşüldüğü anlamına gelir. Oysaki mcu içerisindeki eeprom sadece ayar parametreleri gibi kritik verileri tutmak için vardır.
Eğer çok fazla yaz sil yapılacaksa başka tip harici hafızalar, en kötü harici eeprom kullanılmalıdır.

Verileri sağlıklı olarak tutma kısmından arkadaşlar bahsetmiş. MCU'nun kapanma süresi besleme hattındaki bir kapasitör ile bir müddet korunabilir. Gerekli güç durumuna göre 5.5V'luk süperkapasitör beslemesi kullanılabilir.

Bir diğeri backup. Eğer verilerin bozulma durumu varsa, eepromda da boş yer varsa bir önceki ayarlar hafızada tutturulabilir. Bir arıza durumunda geri dönderilebilir.
Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

yas

#9
Asıl kaygı epromdaki verinin bozulması ise en büyük nedeni gereksiz yere yapılan okumalardır. PIC18 serilerinde çok eskiden başıma böyle bir durum gelmişti. 2-3 yıl bazen daha fazla sorunsuz çalışan üründe ansızın eprom verisinde bozulma meydana geliyordu. Veri düzeltilince sorun düzeliyordu. Bu olayda ilk aklıma gelen epromun bozulduğu düşüncesiydi. Ama ilgincime giden kısım eprom datası tekrar düzeltilip aynı mcu kullandığımız zaman yine normal şekilde çalışmasıydı. Eprom gerçekten bozulmuş olsa o veriyi tekrar tutmaması veya kısa sürede tekrar değişmesi gerekirdi. Sorunun neden kaynaklandığını burasıda dahil bir çok yerde aradım, sonunda yabancı forumların birinde denk geldim. Forum hangisi şuan hatırlayamadım, ama açıklama beni tatmin etti ve bir daha da eprom datasının bozulmasıyla ilgili sorun yaşamadım. Buradaki gözden kaçan kısım epromun tek bir komponent gibi değerlendirilmesi. Halbuki hepimizin de bildiği gibi bütün hafıza birimleri ram,eprom,flash.... adı başka ne olursa artık, transistörlerden meydana gelmekte.

Anlatımın daha anlaşılır olması için basit şekilde örneklemeye çalışacağım umarım çorba etmem  :)
Kalıcı hafızamızdaki her bir bit tutucuyu birer mosfet transistöre benzetelim. Mosfet transistörü ölçü aletimizle nasıl test ettiğimizi herkesin bildiğini varsayarak, drain-source arasını ölçüğümüzde gate in şarj durumuna göre iletimde yada kesimde olduğunu ölçeriz. Transistörün iletim durumunu değiştirmek için tipine göre ölçü aletinin diğer probu sabit kalmak şartıyla + veya - probu gate değdiririz. Transistör iletimde ise imalat özelliklerine göre değişmekle birlikte eğer bacaklarına dışarıdan bir temas olmazsa bir süre daha iletimde kalmaya devam eder taki gate deşarj olana kadar. İşte 100% aynısı olmasa da buna benzer durum eprom içinde geçerlidir. Eproma veri yazarken içerisindeki transistör gruplarının gate erişimi açılır ve bus hattı üzerinden ilgili bitler şarj veya deşarj edilmiş olur. Yazma işlemi yapılmazken bitlere ait transistörlerin gate leri ile bus hattı arasında çok yüksek bir izolasyon söz konusudur.  Hava ile bile temas olmadığını düşünüldüğünde bu bitlerdeki yükün kendiliğinden deşarjı yıllar sürecek bir zaman alır. Şimdi buraya kadar anlatmaya çalıştıklarımla yazma ve saklama aşamalarını tarif etmeye çalıştım. Okuma aşamasını anlatmaya çalışacak olursak, hafıza biriminde okuma yapılırken bu sefer transistörün drain veya source uçları bus hattına bağlanır, kullanılan transistör tipine göre bu uç drain yada source olabilir. Bus hattına hangi uç bağlı ise diğer uçta mcu nun vdd hattına bağlanır. Böylelikle transistörün gate nin şarjlı olup olmaması durumuna göre ilgili transistörler iletimde yada kesimde olurlar. Böylece bus hattında veri oluşturulur. İşte tamda bu nokta o nokta bu işlem sonucunda ister istemez gate te deşarj meydana gelir. Bu deşarjın miktarına bağlı olarak üretici gerekli hesabını yapıp veri sayfasında X adet okumayı yada saklama süresini garanti eder.
Özetle yaptığımız ürün sadece açılışta epromu okuyup içeriği değişkenlere alıp runtime esnasında eprom verisi değiştirilmedikçe epromu okumayla ilgilenmiyorsa epromu en uzun süreyle kullanabilir. Mutlaka aramızda da vardır diye düşünüyorum. Öyle gereksiz yere epromu okuyanlarımız var ki her 5 saniyede epromdaki veriyi kontrol eden bile var.
Epromdaki Deşarj olayı engellenemez mi? şeklinde gelecek sorulara cevaben hayır engellenemez ama sorun çözümsüz değil. Çözüm yine epromda bir sayaç tutmaktan geçiyor. Diyelim ki epromu her okuduğumuzda bu sayacı +1 yaparız. Okuma rutinimize girdiğimizde sayacımızın da üst sınırını kontrol ederiz. Mesela 10000 i geçince okuduğumuz epromu tekrar yazar (yani transistörlerin gate lerini şarj eder) ve sayacımızı sıfırlarız.
En kısa şekilde anlatmak istedim ama ne kadar anlaşır oldu bilemiyorum.

Tagli

#10
@yas , az önce baktım da, PIC datasheet'lerinde iki ayrı parametre olduğu gözüme çarptı. Örneğin PIC16F1827'de:

[D116] [ED] Byte Endurance -> 100K (min) - 1M (typ)
[D120] [TREF] Number of Total Erase/Write Cycles before Refresh -> 1M (min) - 10M (typ)

Datasheet'te net bir açıklama yok. İnternette farklı yorumlar yapılmış. Hepsini beraber düşününce vardığım sonuç şu: Her bir byte'ın 1M ömrü var. Ancak EEPROM'a yapılan yer bir yazma, nereye yapılırsa yapılsın, 10M'lik bir toplam ömürden de eksiltiyor. Bu ömrün sonunda, mesela sadece 1 kez yazılıp öyle bırakılmış bir adresteki veri bozulabiliyor. Sanki bir şekilde elektrik yükünü kaybediyor 10M yazmanın sonunda. Bunun için, hiç değişmeyen verilerin bile EEPROM'da toplam 10M yazma oluşmadan bir yenilenmeleri, yani aynı değerin tekrardan yerine yazılması gerekiyor.

Burada yanlış anlaşılma olmasın, EEPROM'un toplam 10M yazma limiti yok. Tek bir byte hücresi için bakarsak, bu byte 1 kez yazıldıktan sonra EEPROM'un başka yerlerine toplamda 10M yazma yapılırsa, bu yazdığımız byte durduğu yerde bozulabiliyor. Bunu engellemek için 10M yazma dolmadan bu byte'ı yeniden güncellememiz gerekiyor. Ama tabi yanlış anlamış da olabilirim.
Gökçe Tağlıoğlu

Okan AKÇA

Durmadan yazma silinme gibi durum Söz konusu ise  ram eprom özellikli ürünler kullanilmalidir

Tagli

Ben zaten flash ve EEPROM'u periyodik değişen değerler için değil, kullanıcı parametreleri & ayarları için kullanıyorum genelde. Uygulamalarımda 100K - 1M gibi sayılara ulaşacağımı sanmıyorum. Yine de, bu iki bellekle yapabileceklerimizin sınırlarını keşfetmek faydalı olacaktır.
Gökçe Tağlıoğlu

yas

#13
Alıntı yapılan: Tagli - 07 Şubat 2022, 09:15:53...Bu ömrün sonunda, mesela sadece 1 kez yazılıp öyle bırakılmış bir adresteki veri bozulabiliyor. Sanki bir şekilde elektrik yükünü kaybediyor 10M yazmanın sonunda. Bunun için, hiç değişmeyen verilerin bile EEPROM'da toplam 10M yazma oluşmadan bir yenilenmeleri, yani aynı değerin tekrardan yerine yazılması gerekiyor.

Burada yanlış anlaşılma olmasın, EEPROM'un toplam 10M yazma limiti yok. Tek bir byte hücresi için bakarsak, bu byte 1 kez yazıldıktan sonra EEPROM'un başka yerlerine toplamda 10M yazma yapılırsa, bu yazdığımız byte durduğu yerde bozulabiliyor. Bunu engellemek için 10M yazma dolmadan bu byte'ı yeniden güncellememiz gerekiyor. Ama tabi yanlış anlamış da olabilirim.

Evet önceki mesajda da anlatmaya çalıştığım buydu. Epromun hiç erişilmeyen yada en az erişilen bölgesinin bile bir sonra yenilenmesi gerekli. Çünkü zaman içerisinde statik yükünü kaybedebilir. Ayrıca üreticilerin belirtiği değerler sadece verdikleri garantiyi yansıtıyor. En az 1M 10M gibi.

Birde yukarıdaki mesajlarda dinamik verilerin ramda kullanılması gerektiğine vurgu yapılmış. Yanlış anlaşılmasın tabi ki öyle olması gerekli, ben sadece gereksiz yere kullanımları yapanların varlığından bahsetmek istemiştim yoksa benimsemdiğim bir yöntem değil.

kantirici

@yas'ın belirttiği durum komponente göre çok fark ediyor. Mesela 24AA65 ürünü için datasheet: "Data Retention > 200 years" demiş.

Ayrıca bazı algoritmalar ile bir bitlik veri bozulmaları telafi edilebiliyor. Ama bu kadar önemli işler yapıyor muyuz? sanmıyorum :)