24c eprom write cycle time?

Endorfin35+

Kayıtsız Üye
Katılım
1 Mayıs 2020
Mesajlar
4,211
24CXX serisi epromlar hakkinda bilgisi olan var mi?

24c32 yi arduino mega bagladim. i2c uzerinden birde kutuphane yukledim. Bir dongu ile 4k veri yazdim. Aninda islem tamamlandi. Verileri okudum. Yazma basarili olmus. Buraya kadar hersey guzel.

Sonra kutuphaneden birsey dikkatimi cekti byte byte iki yazma arasina 10ms write cycle time olmasi gerekir yazmis. Koydum 10ms. Benim islem 40 saniye surdu. Cok fazla... Sonra daldim biraz isin teknigine ograndigim kadari ile ilk basta mikrosaniye mertebesinde hizli iken eprom yaslandikca yazma suresi uzuyormus. Benim bilgiler ilerde yazilmazmi nasil bu isi optimize etmeliyim derdi basladi...

Eprom Kutuphanesini kaldirdim. i2c uzerinden kendim dogrudan haberlesmeye basladim.

Temel mantik soyle eproma her byte veri gittiginde eprom cevap olarak tamam abi (ack) diyor. i2c den bu kimin adresi diyorsun. Burdayim diyor. Sonra epromda 4k adres oldugundan adresi 2byte lik bir degisken ile 1byte 1 byte ayirip gonderiyorsun. Eprom yine tamam cevabi veriyor. Sonra 1byte veri gonderiyorsun. Eprom tamam diyor.

Yazma zamani ile ilgili Datasheet derki epromdan bir talepte bulundugunda yazma isi ile mesgul ise sana cevap vermez. Adres/byte seklinde veri yazdigimda her seferinde bana cevap veriyor. Demekki sorun yok. O zaman neden 10ms koy araya demis kutuphane yazan arkadas orda kafam karisiyor. Tabi i2c icin arduino nun wire.h kutuphanesini kullaniyorum. Baska biride demiski wire.h icin 32byte buffer var. 32 den fazla gonderme...

Yazarkende dusunuyorum bir yandan... O zaman ben her byte sonunda i2c yi sonlandirip yeniden baslatiyorum. Ben simdi ne yapacam..?

İ2c den talep gonderigimde cevap gelmez ise kutuphane nasil davraniyor ona bakiyim ne olacak...
 
Sabit bir gecikme mantıklı değil. Dediğin gibi yazma işlemini EEPROM'un ACK'laması lazım. Eğer "page write" modu varsa, bir hamlede bir blok veri gönderip ACK bekleyebilirsin ve böylece blok blok yazmış olursun. Ama yoksa tek tek byte yazılması lazım.

İstersen datasheet ekle oradan beraber irdeleyelim.
 
Aslında daha doğrusu ACK değil de, EEPROM'da bir status register oluyor ve oradaki bir bit, bir önce başlatılan komutun tamamlandığını ifade ediyor. Yani yazma komutunu gönderiyorsun, sonra da sürekli status register okuması yapıyorsun, ta ki "komut tamamlandı" biti set olana kadar. Eğer datasheet'te ASGARİ bir yazma süresinden bahsediliyorsa, o süreyi delay ile bekleyip sonradan status register okuma döngüsüne de girilebilir. Ama bence gerek yok, doğrudan status register poll etmek genel bir çözüm.
 
Elimdeki Ürün :Atmel 24c32

Atmel Datasheet

ST Datasheet (Sayfa 19)

ST nin dökümanı daha iyi sanırım.

Ben biraz uğraşıyım. Takılırsam yardım, halledersem teyit isterim. :D (illa birşey isteyecem)
 
Tamam bunda page write modu var. 32 bytelık lokmalar halinde yazabilirsin.
 
Olayı çözdüm sanırım :)

Önce klasik kodu ekleyeyim;
Kod:
#include <Wire.h>  

#define disk1 0x57    //Address of 24LC256 eeprom chip

void setup(void)
{
  Serial.begin(9600);
  Wire.begin();

  unsigned int address = 3000;

  writeEEPROM(disk1, address, 123);
  Serial.print(readEEPROM(disk1, address), DEC);
}

void loop(){}

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data )
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();

  delay(5);
}

byte readEEPROM(int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;

  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();

  Wire.requestFrom(deviceaddress,1);

  if (Wire.available()) rdata = Wire.read();

  return rdata;
}

Bu kod düzgün çalışıyor. İstenen adrese veriyi yazıp sonrada okuyor. Ancak yazma işleminin sonuna 5ms bekleme eklenmiş. Beklemeyi kaldırınca kod yanlış çalışıyor. Okuma yapamıyor.

Datasheetlerde Epromun meşgul olduğunu bildiren herhangi bir status register göremedim. Ancak eprom meşgul ise sana ACK göndermez denmiş. Şimdi wire.h kütüphanesinin Wire.endTransmission() fonksiyonun aldığı değerlere bakalım.

Kod:
/*
Wire.endTransmission()
0:success
1:data too long to fit in transmit buffer
2:received NACK on transmit of address
3:received NACK on transmit of data
4:other error
*/

Fonksiyonun 0 aldığı durum ACK nın alındığını gösteyiyor. O halde gittiğim çözüm bekleme yerine her işlemden önce while döngüsü ile epromdan ACK talep etmek oldu. Alternatif olarak 2 veya 3 değeri için tekrar deneme de olabilirdi.

Kod:
void eprom_yaz(int i2c_adres, unsigned int e_addres, byte data )
{
  I2C_Kontrol(i2c_adres);
  Wire.beginTransmission(i2c_adres);
  Wire.write((int)(e_addres >> 8));   // MSB
  Wire.write((int)(e_addres & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();

  //delay(5);
}

byte eprom_oku(int i2c_adres, unsigned int e_addres )
{
  byte okunan_veri=0;;
  I2C_Kontrol(i2c_adres);
  Wire.beginTransmission(i2c_adres);
  Wire.write((int)(e_addres >> 8));   // MSB
  Wire.write((int)(e_addres & 0xFF)); // LSB
  Wire.endTransmission(); 
  Wire.requestFrom(i2c_adres,1);

  if (Wire.available()) okunan_veri = Wire.read();

  return okunan_veri;
}

void I2C_Kontrol(int i2c_adres)
{
    bool durum=0;
   
    unsigned long sure = millis();
   
    while(durum==0 && millis() - sure <= 5000)    // 5 saniye
    {
      Wire.beginTransmission(i2c_adres);
      durum = !Wire.endTransmission();
    }

    if (durum==1) return;
    //if (durum==0) time out oldu birşeyler yap..!

}
}

Bu düzenleme ile delay kaldırdığımda kod düzgün çalışmaya başladı. 1bayt yazma ve ardından okuma için işlem süresini ayrıca ölçtüğümde 2ms sürdüğünü görüyorum. tüm epromu doldurum kontrol ettim. 4k için 7-8 saniye sürüyor. Sanırım optimum bir süre. İşyerinde bire bir aynı modul var ama üzerindeki eprom farklı marka. onunda daha da hızlı oldu/olacak sanki ama şu an yanımda olmadığı için emin değilim. Page yazma konusunda tecrübem yok. bendeki veriler yığın olmadığı için bana uygun olmadığını düşünüyorum.


Genel olarak eprom kullanımı ile şöyle bir yaklaşımım var. Kendim için bir eprom adresi belirlerim. örneğin 198. Sonra bu adrese kendi belirlediğim bir sabit yazarım. örneğin 55. Sonra ilk çalışmada gider bu adresi sorgularım. Adreste kendi değerimi bulamazsam tüm epromu silerim. Sonra koddaki varsayılan değerleri eproma yazarım. Ardından da kendime özel adrese ayak izimi bırakırım. Her türlü ihtiyacım olan verileri kod başında epromdan çekerim. ayak izi varsa doğrudan oku ayak izi yoksa önce organize et sonra oku. Bu epromu silme işlemi normalde sadece bir kere ilk kullanımda oluyor. kullanıcı parametre değiştirdikçe epromuda güncelliyorum. böylece parametreler hep hafızada kalıyor.

@taydin hocam birşey sorma hakkımı saklı tutmak istiyorum :D
 
Evet dediğin gibi, bunda bir status register yok. Onun yerine sürekli I2C START gönderip ACK'leyene kadar bekliyorsun. EEPROM verilerinin bozulmadığını doğrulamak için belki bir de CRC checksum düşünebilirsin.
 
Peki konu eprom olunca başka bir şey sorayım.

1 baytlık verimiz var. epromda log için sıralı 50byte yer ayırdık. hergün sıradan ilk boşluğua 1 byte yazıyoruz. istersek bloğu okuyup rapor olşturuyoruz. 50 gün sonra yer kalmadı ne olacak :cheeky2:

Olmasını istediğim en eski kaydın silinmesi ve yeni verinin yazılması. Böylece sürekli son 50 kayıt olacak. Hemde sıralı olsun (nasıl olacaksa?)

Burda nasıl bir mantık olacak emin değilim. Şu ana kadar en çok aklıma yatan çözüm. belirlenen kayıt kapasitesinin iki katı hafıza ayırmak sürekli ve verileri sürekli sıralı tutmak. şöyle 50 kayıt için 100 byte ayırdık. 100 e kadar veri kaydettik ama hep son 50 yi okuduk. 100e ulaşınca ilk 50 yi silip 50-100 arasını ilk 50 nin yerine taşıdık. yeni kayıtları 50 den itibaren atmaya devam sürekli son 50 yi oku.. 100 e ulaşınca tekrar başa kaydır yer aç.

Avantajı: bilgiler sürekli sıralı. sıralama için ekstra kodlama yok. sıra numarası kaydetmek yok vs.
Dez avantaj : iki kat kapasite ayırma, 100 ulaşınca kayıtların aktarımı için nispeten zaman kaybı..
 
Ben olsam mesela 100 byte lık yer ayırırım. Bir index ile de bu yere yazarım. Yer dolunca da bir flag set ederim. Bu flag'ın anlamı "100 den fazla olay oldu, ama sadece son 100 olay kayıtlı".

C:
static unsigned char events[100];
static unsigned int pos = 0;
static int overflow = 0;

void log_event(unsigned char event)
{
    if (pos >= sizeof(events))
    {
        overflow = 1;
        pos = 0;
    }

    events[pos++] = event;
}
 
Buradaki events, pos ve overflow, eeprom'a yazılması gerekiyor. Bu yazma işini kolaylaştırmak için tüm EEPROM verilerini bir struct içine de koyabilirsin:

C:
typedef struct
{
    unsigned char events[100];
    unsigned int pos = 0;
    int overflow = 0;

} EEPROM_IMAGE;

static EEPROM_IMAGE ee_image;

*
*
*

log_event(EVENT_BROWNOUT);
EEPROM_write(&ee_image, sizeof(ee_image));

*
*
*
 
24CXX serisi bende 2K ve 4K 2-3 tane eeprom var. Konuyla çok bir fikrim yolmadığını fark ettim bir ara bende tecrübe etmek için kullanayım. :popcorn1:
 
Burada yalnız şöyle önemli bir varsayım var: Sen endüstriyel bir sistemin bir bileşeni olan bir devre üzerinde çalışıyorsan, o devrenin ya yedek pil beslemesi olacak yada UPS üzerinden her zaman besleme voltajı olacak. O yüzden komple EEPROM image okuyup üzerinde çalışıp geri yazabilirsin.

Ama örneğin benim çalıştığım sistemler hep son kullanıcıların kullandığı ev tipi sistemler. Yedek akülü besleme de yok UPS garantisi de yok. O yüzden benim EEPROM ile çalışırken, her zaman tam yazmanın ortasında enerjinin kesilebileceğini varsayıp ona göre EEPROM verilerini güncellemem gerekir. Elektrik hangi noktada kesilirse kesilsin, EEPROM tutarsız bir duruma gelmemeli, en fazla yazılması gereken veri yazılamamış, bir önceki veriler ise sağlam durumda olmalı.
 
Sistemde pil var ama ani kesintide sadece mcu ve epromu 3-5 saniye destekleyecek kondansator kullanmayi dusunuyorum. İstedigim gibi olmaz ise pilden bypass ederim.
 
@taydin CRC dedin veri yazılmaz dedin işgillendirdin beni. :oops:

aşağıdaki yapı ile kesntide yeteri zamanı elde ettik. veriyi yazdık. birde üzerine okuduk. doğruladık. Yani veri yazarken kesinti olmasını beklemiyorum. başka bir tedbir almak gerekliimi? Yazdığımı okuyamıyorsam (daha kesinti olmadan) o zaman eprom bozulmuştur. Aklıma başka sorun gelmiyor.


1601153190366.png
 
Eğer her parametrenin birbiri ile uyumluluğunu ve tutarlılığını kontrol edebiliyorsan, yani mantıklı parametreler olduğunu test edebiliyorsan, aslında CRC ye gerek yok. En fazla ne olur? Sistem güvenli bir şekilde, ama yanlış modda veya yanlış yapılandırma ile çalışır. Ama bu tutarlılığı kontrol etmeye yazılımın aklı yeterli değilse, o zaman CRC mutlaka gerekli, yoksa sistem tehlikeli parametreler ile çalışabilir (aşırı devir, aşırı sıcaklık vs).
 
Sanırım GPIO interrupt ile enerji kesildiğini anlayıp hemen EEPROM'u kaydetmeyi değerlendiriyorsun. Burada birçok senaryo var. Tam olarak her durumda güvenli bir şekilde çalışacağının bir garantisi yok. Mesela şu senaryoyu düşün: Elektrik kesildi, ve kapasitör kritik voltaja düşüp tam MCU off olmadan önce EEPROM'a yazma başladı. Yazma yarıda kalacak.

Diyelim GPIO yu kesme olarak yapılandırdın ve enerji kesildi, interrupt'a girdin. Ya tam olarak ana kod EEPROM'a yazmanın ortasında iken kesme geldiyse?

O yüzden ya MCU yu sürekli canlı tutacak bir pil olması lazım, yada EEPROM yazmalarını öyle bir sıralıyacaksın ki, elektrik nerede kesilirse kesilsin EEPROM içeriği tutarlı kalacak. En fazla, en son olay kaydedilmemiş olacak.
 
Seytan ayrintida gizli diyorsun. :D

Yazma ortasinda kesime gitmesini kodla cozerim.
Kondansatoru buyuk secerim. 10sn dayansa rahat rahat yeter. Ama oldu bozuldu... Sayac verikilerini ust uste yazmayi dusunuyordum. Bu kotu bir fikirmis. Arabanin km sayaci gibi dusun. Araban 80binde o gun 50km yaptin. Silip 80050 yazarken bir sikintida 80binde gider. Ya iki ayri adreste yedekli bir sey yapmaliyim. Yada iki ayri eprom kullanmaliyim. Her sekilde bir yedek yaratmaliyim o zaman..
 
Aklim karisti. Bana basit bir ornek verebilirmisin.

Basit (1byte)dusunelim. 5,6 ve 7 adrslerini nunarator icin ayirdim.
7. Nolu adrste numarator verisinin 5 denmi 6 danmi okuyacagim verisi var acilista 7. Nolu adresten 5 degerini okudum. Sonra gittim
5. Nolu adresten numarator verisini okudum degiskene cektim. 35 olsun. Makina calisti nunarator 48 oldu.

Kapanis algiladim. Onceki veriyi 5 ten okudugumu bildigim icin gittim 6 ya numaratoru yazdim. Geri okudum ayni veri var. En son gittim 7 nolu adrese sinraki acilis icin 6 yazdim. İsim bitti.

6 yazdiysam sikinti yok. Yazmadiysam 5 nolu adresteki veriden devam...

Mantikli mi?
 
Aklim karisti. Bana basit bir ornek verebilirmisin.

Basit (1byte)dusunelim. 5,6 ve 7 adrslerini nunarator icin ayirdim.
7. Nolu adrste numarator verisinin 5 denmi 6 danmi okuyacagim verisi var acilista 7. Nolu adresten 5 degerini okudum. Sonra gittim
5. Nolu adresten numarator verisini okudum degiskene cektim. 35 olsun. Makina calisti nunarator 48 oldu.

Kapanis algiladim. Onceki veriyi 5 ten okudugumu bildigim icin gittim 6 ya numaratoru yazdim. Geri okudum ayni veri var. En son gittim 7 nolu adrese sinraki acilis icin 6 yazdim. İsim bitti.

6 yazdiysam sikinti yok. Yazmadiysam 5 nolu adresteki veriden devam...

Mantikli mi?

Bence mantıklı. Ama hep aynı EEPROM adresini sürekli değiştirdiğin için EEPROM'u aşındırıyorsun. Bence şu daha mantıklı:

EEPROM içinde bir buffer ayırdın. Bir byte numaratör, sonraki byte flag ve bu flag'ın anlamı, "son değer budur". Yani numaratör, flag, numaratör, flag diye gidiyor.

Yeni bir değer yazacağın zaman, yeni yere yazıyorsun, yanındaki flag'ı set ediyorsun, bir öncekinin flag'ını clear ediyorsun. Yani üç aşamada yeni değeri yazmış oluyorsun.

1) Yeni numaratörü yaz (bu birden fazla byte da olabilir aslında sorun değil).
2) Yeni numaratörün flag'ını set et.
3) Bir önceki numaratörün flag'ını clear et.

Şimdi analiz edelim:

1. den önce enerji gitti, EEPROM değişmiyor, sorun yok.
1 in ortasında enerji gitti, kısmi bir numaratör değeri yazıldı, ama flag set edilmediği için önceki numaratör hala geçerli. Gene sorun yok.
1 ve 2 arasında enerji gitti. Tam bir numaratör değeri yazıldı, ama flag set edilmediği için önceki numaratör hala geçerli. Gene sorun yok.
2 nin ortasında veya 2 ve 3 arasında enerji gitti. Flag yazılmadan gitti ise bir önceki numaratör hala geçerli. Flag yazıldıktan sonra gittiyse, iki tane set flag olacak. Bu durumda ikinci flag'ın güncel numaratöre işaret ettiğini varsayıyorsun. Enerji gelip de bu durum ile karşılaştığında tabi yarım kalmış işi tamamlayıp bu bir önceki flag'ı silmek lazım. Gene bu arada enerji giderse gene sorun yok :D Bir sonraki power cycle'dan sonra yarım işi bitirirsin.
3 ten sonra enerji gitti, bu durumda zaten işlem tamam, tek flag var ve yeni numaratörü işaretliyor.
 
hep aynı EEPROM adresini sürekli değiştirdiğin için EEPROM'u aşındırıyorsun.

Asindirma konusunda sunu merak ediyorum. Yazarken asiniyor. Okurken asinma yok mu? Veya Okurken asinma ilhmal edilecek kadar az mi?

Yukaridaki seneryoda 1-20 arasi buffer olsun.
Tek rakamlarda 1,3,5,7 de datayi saklalim.
2,4,6,8... Da bayrak set edelim.

Mantik su degil mi buffer kapasitesi kadar dongu icinde bayragi ara. Buldugunda bir oncekinden datayi oku..

Bu durumda bayrak nere diye epromu tararken okuma asinmasini merak ettim...
 

Forum istatistikleri

Konular
5,983
Mesajlar
102,053
Üyeler
2,516
Son üye
adu33

Son kaynaklar

Son profil mesajları

deneyci wrote on hakan8470's profile.
Sibonge uNkulunkulu ngokuhlukahluka asinike kona.

Bu hangi dil? :)
Lyewor_ wrote on taydin's profile.
Merhabalar. Elektrik laboratuvarınız varsa bunun hakkında bir konunuz var mı acaba? Sizin laboratuvarınızı merak ettim de :)
Lyewor_ wrote on taydin's profile.
Merhabalar forumda yeniyim! Bir sorum olacaktı lcr meterler hakkında. Hem bobini ölçen hemde bobin direnci ölçen bir lcr meter var mı acaba?
gruptaki arkadaşlara selamlar. sıteyi bu gün fark ettim. Asansör için 2x7 segment LCD gösterge üretmek istiyorum. acaba bu sayfadaki arkadaşlardan destek alabilirmiyim. LCD nin mantık açılımı ektedir.
deneyci wrote on TA3UIS's profile.
Selam.
Amatör telsiz lisansı nasıl alınıyor?
Lisansı olmayanı forumlarına almıyorlar. :)
Bilgi alamıyoruz.
Back
Top