24LC32A EEPROM Özellikleri ve STM32 İle Kullanımı

  • 27-06-2020 03:30
  • 814

24AA32A ve 24LC32A Microchip firmasının ürettiği 32Kbit'lik I2C seri EEPROM bellektir. EEPROM belleklerde enerji kesilsede içindeki veriler silinmez, günümüzde kullanılan flash belleklere benzer. Farklı olarak yeniden yazma limitleri ve veri tutma süresi flashlardan çok daha yüksektir. Ortalama bir flash bellekte yeninen yazma limiti 10.000 veri tutma süresi yaklaşık 20 yıldır. 24LC32A'da ise yeniden yazma limiti 1.000.000 veri tutma süresi ise 200 yıldır. Limitler ne kadar yüksek de olsa sürekli veri kaydı yapılacak uygulamalarda RAM bellek gibi kullanılamazlar. Daha çok uygulamalarda kullanıcının kaydettiği verileri tutmak için kullanılır. Örneğin saat uygulamasında alarm saatini tutmak için ya da radyo uygulamasında kanal frekanslarını ve isimlerini tutmak için kullanılabilir. Bu sayede enerji kesilsede kullanıcı verileri silinmez. Teknik özelliklerin ayrıntılarına bu sayfadan ulaşabilirsiniz datasheet.

I2C Cihaz Adresi

24LC32A mikrodenetleyiciye I2C seri protokolü ile bağlanır, okuma ve yazma işlemleri bu protokolde gerçekleşir. Her I2C destekli cihazda olduğu gibi 24LC32A'nında 7 bitlik bir slave adresi vardır bu adres 0xA0 dan başlar ve A0,A1,A2 girişlerişne uygulanan veri ile 0xAE adresine kadar (2'nin katları şeklinde) 8 farklı adres olabilir. Bir tane bellek kullanıldığında ve 0xA0 adresi ile başka bir adres çakışmadığında bu adres A0,A1,A2 girişleri GND'ye bağlanarak kullanılabilir.

Veri Yazma

I2C portuna cihaz adresi ile birlikte yazma modunda açılır. Verinin kaydedileceği 2 baylık adresin önce yüksek öncelikli baytı gönderilir, ardından düşük öncelikli baytı gönderilir son olarak kaydedilecek 1 baylık veri gönderilir ve I2C kapatılır.

Veri Okuma

I2C portuna cihaz adresi ile birlikte yazma modunda açılır. Okunacak verinin 2 baytlık adresin yüksek öncelikli baytı gönderilir ardından düşük öncelikli baytı gönderilir. I2C okuma modunda yeniden açılır adresteki 1 baytlık veri okunur ve I2C kapatılır.

STM32 Örnek Kod

Kod STM32F10X için yazılmıştır. Önce EEPROM'un bağlantılarını yapmalısınız. Bu örnekte EEPROM I2C1'e bağlıdır, EEPROM'un SCL pini STM32'nin B6 pinine SDA B7 pinine bağlanmalı EEPROM'un A0,A1,A2,WP pinleri GND'ye ve son olarak güç bağlantıları VCC VCC'ye GND GND'ye bağlanmalı. Örnek derlendiğinde çıktı vermeyecek şekilde çalışır. Kendi geliştirme kartınıza bağlı bir ekran varsa örnekteki açıklamalara bakarak uygun yerlerde kendi ekrana yazma fonksiyonunnuzu kullanıp çıktıyı ekranda görebilirsiniz.

 

#include "stm32f10x.h"
#include <stm32f10x_i2c.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_tim.h>



#define EEPROM_ADDRESS  0XA0
#define I2C_PORT     I2C1

#define I2C_TIME_OUT 40000


/*
 * Yeniden yazma için EEPROM resetleniyor.
 */
static uint32_t EEpromResetWrite(){
	uint32_t t_out=0;
	uint32_t t=0;

	while(t<100){
		I2C_GenerateSTART(I2C_PORT, ENABLE);
		t_out=0;
	    while(!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT))
	    {
	        t_out++;
	        if(t_out>I2C_TIME_OUT){
	        	return 1;
	        }
	    }

	    I2C_Send7bitAddress(I2C_PORT, EEPROM_ADDRESS, I2C_Direction_Transmitter);
	    t_out=0;
	    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) && t_out<I2C_TIME_OUT)
	    {
	      t_out++;
	    }
	    if(t_out<I2C_TIME_OUT){
	    	I2C_GenerateSTOP(I2C_PORT, ENABLE);
	    	return 0;
	    }
	    t++;
	}
	return 2;
}


/*
 * Fonksiyon 24LC32A, 24AA32A EEPROM bellekten veri okur.
 * Fonksiyon parametreleri:
 * address: Okunmak istenen verinin adresi 16 bit.
 * value  : Okunan verinin kaydedileceği pointer.
 * Dönüş değeri: 0 ise işlem başarılı diğer bütün olasılıklar
 * hata oluştuğu anlamına gelir.
 *
 */

uint32_t  EEpromReadByte(uint16_t address,uint8_t * value){
	 uint32_t t_out=0;
	 uint8_t high_byte,low_byte;

	high_byte=address>>8;
	low_byte=address&0xFF;


    while (I2C_GetFlagStatus(I2C_PORT, I2C_FLAG_BUSY))
    {
      t_out++;
      if(t_out>I2C_TIME_OUT){
    	  I2C_GenerateSTOP(I2C_PORT, ENABLE);
    	  return 2;
      }
    }
/*
 * Her mod değişiminde ayarlanan süre içinde modun değişmesi bekleniyor.
 * Bu süre içinde mod değişimi gerçekleşmezse fonksiyondan çıkılıyor.
 *
 */

	//I2C bağlantısı açılıyor.
	t_out=0;
	I2C_GenerateSTART(I2C_PORT, ENABLE);
    while(!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT))
    {
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 1;
        }
    }

    //Veri göderme modu seçiliyor.
    I2C_Send7bitAddress(I2C_PORT, EEPROM_ADDRESS, I2C_Direction_Transmitter);
    t_out=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
    {
      t_out++;
      if(t_out>I2C_TIME_OUT){
    	  I2C_GenerateSTOP(I2C_PORT, ENABLE);
    	  return 2;
      }
    }

    //Adresin ilk baytı gönderiliyor.
    I2C_SendData(I2C_PORT, high_byte);
    t_out=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 3;
        }
    }

    //Adresin ikinci baytı gönderiliyor.
    I2C_SendData(I2C_PORT, low_byte);
    t_out=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 4;
        }
    }


    //I2C yeniden başlatılıyor.
	I2C_GenerateSTART(I2C_PORT, ENABLE);
	t_out=0;
    while(!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT))
    {
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 5;
        }
    }


    //Veri okuma modu seçiliyor.
    I2C_Send7bitAddress(I2C_PORT, EEPROM_ADDRESS, I2C_Direction_Receiver);
    t_out=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
    {
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 6;
        }
    }

    I2C_AcknowledgeConfig(I2C_PORT, ENABLE);

    //Bir bayt veri okunuyor.
    t_out=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_RECEIVED)){
        t_out++;
        if(t_out>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 7;
        }
    }

    //Veri değişkane kaydediliyor.
    *value=I2C_ReceiveData(I2C_PORT);

    I2C_AcknowledgeConfig(I2C_PORT, DISABLE);

    //I2C kapatılıyor.
    I2C_GenerateSTOP(I2C_PORT, ENABLE);

    return 0;

}






/*
 * Fonksiyon 24LC32A, 24AA32A EEPROM belleğe veri kaydeder.
 * Parametreler:
 * address: Verinin kaydedileceği adres (2 bayt).
 * data   : Kaydedilecek veri (1 bayt).
 * Dönüş değeri: 0 ise işlem başarılı diğer bütün değerler hata
 * oluştuğu anlamına gelir.
 *
 */
uint32_t EEpromWriteByte(uint16_t address,uint8_t data){

	volatile uint32_t t=0;
	volatile uint8_t high_byte,low_byte;

	high_byte=(address>>8)&0xFF;
	low_byte=address&0xFF;


    //I2C bağlantısı açılıyor.
	I2C_GenerateSTART(I2C_PORT, ENABLE);
	t=0;
    while(!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_MODE_SELECT))
    {
        t++;
        if(t>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 1;
        }
    }



    //I2C bağlantısı 7 bitlik adres ile yazma modu seçiliyor.
    I2C_Send7bitAddress(I2C_PORT, EEPROM_ADDRESS, I2C_Direction_Transmitter);
    t=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
    {
      t++;
      if(t>I2C_TIME_OUT){
    	  I2C_GenerateSTOP(I2C_PORT, ENABLE);
    	  return 2;
      }
    }

    //Verinin yazılacağı adresin ilk baytı gönderiliyor.
    I2C_SendData(I2C_PORT, high_byte);
    t=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
        t++;
        if(t>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 3;
        }
    }

    //Adresin ikinci baytı gönderiliyor.
    I2C_SendData(I2C_PORT, low_byte);
    t=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
        t++;
        if(t>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 4;
        }
    }



    //Yazılacak veri gönderiliyor.
    I2C_SendData(I2C_PORT, data);
    t=0;
    while (!I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
        t++;
        if(t>I2C_TIME_OUT){
        	I2C_GenerateSTOP(I2C_PORT, ENABLE);
        	return 5;
        }
    }

    //I2C bağlantısı kapatılıyor.
    I2C_GenerateSTOP(I2C_PORT, ENABLE);


	//EEprom resetleniyor.
	if(EEpromResetWrite()){
		return 11;
	}

    return 0;
}







/*
 * Fonksiyon I2C bağlantısını yapılandırır.
 */
void I2CInit(void){

    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitStructure;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    //B portu yapılandırılıyor.
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open Drain, I2C bus pulled high externally
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //I2C resetleniyor.
    I2C_DeInit(I2C1);

    //I2C aktif hale getiriliyor.
    I2C_Cmd(I2C1, ENABLE);

    //I2C yapılandırılıyor.
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x039;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 200000;
    I2C_Init(I2C1, &I2C_InitStructure);

}


int main(void) {

    uint8_t text[]="0123456789";
    uint8_t ch[11];
    uint16_t u=0;
    uint16_t e=0;

    //I2C arabirimi yapılandırılıyor.
    I2CInit();

    //Bu döngüde text dizisindeki 10 karakter EEPROM'a kaydediliyor.
    //Döngüde kullanılan u değişkeni aynı zamanda adres olarak kullanılıyor.
    for(u=0;u<10;u++){
	//EEPROM'a 1 bayt yazılıyor.
	 e=EEpromWriteByte(u,text[u]);

	 //Hata kontrol ediliyor.
	 if(e){
		 //Hata oluştuğunda program sonsuz bir döngüye girer.
		 //Hata kodu e değişkeninde kayıtlı.
		 while(1);
	 }
	}


	//Bu döngüde EEPROM'dan 10 bayt veri okunuyor ve ch dizisine kaydediliyor.
	for(u=0;u<10;u++){
		 e=EEpromReadByte(u,&ch[u]);
		 //Hata kontrol ediliyor.
		 if(e){
			 //Hata oluştuğunda program sonsuz bir döngüye girer.
			 //Hata kodu e değişkeninde kayıtlı.
			 while(1);
		 }
	}
	//Okunan karakterler  0  sonlandırılıyor.
	ch[u]=0;

	while(1){
		//ch dizisine EEPROM'dan okunan veriler kaydedildi.
		//printf("%s",ch); örneğinde olduğu gibi kendi ekrana yazdırma
		//fonksiyonunuzla diziyi burada ekrana yazdırabilirsiniz.
	}


	return 0;
}