mini2440----keil for AMR之IIC讀寫EEPROM(AT24C08)

文章大綱:

一:EEPROM芯片介紹(包括各種讀寫的時序與管腳定義)

二:S3C2440中對於IIC需要配置的寄存器

三:IIC成功讀寫EEPROM的程序(光盤的那個IIC讀寫程序真心對初學者不好理解)

 

一:EEPROM芯片介紹

在這裏分析AT24C02A/AT24C04A/AT24C08A,對於其他不同型號的EEPROM芯片要根據具體手冊進行分析。他們的大小分別是2K(256*8)/4K(512*8)/8K(1024*8)因此可以看出實際大小是256/512/1024byte,。對於AT24C02A的三位地址線都是寫死的,因爲在進行讀寫操作時使用8位地址已經足夠,所以三位地址線寫死作爲片選,對於AT24C08A的三位地址線第一位必須寫死,後兩位可以作爲內部頁地址。因爲AT24C08A的大小超過了256byte,8爲尋址,已經沒法使用到芯片內所有的空間。因此對於後面兩位也就可以由程序決定了。

EEPROM有兩種,(在寫數據的時候,AMR9作爲主設備,EEPROM是從設備)

第一種寫byte方式

寫一個byte實際上需要發送三次數據。在這個過程中,主設備爲發送狀態。第一個數據——設備地址。第二數據——ARM9想寫的EEPROM中的地址。第三個數據——想寫入到EEPROM中的具體數據。最後停止。

第二種寫頁方式

自我感覺其實寫頁與寫byte應該是一致的,第一個數據——設備地址。第二數據——ARM9想寫的EEPROM中的地址(但是這個地址是首地址。AT24C02一頁是8byte,AT24C04/08一頁是16byte。所以在寫頁的時候最多寫一頁的大小,如果寫太多就會重新又從首地址開始,以前寫的會被覆蓋掉。)。第三、四、······數據——就是你想寫入到EEPROM中的數據。最後停止

EEPROM中的數據

第一種讀當前地址數據

主設備仍然是ARM9,從設備是EEPROM,但是要注意主設備的狀態有時候會是發送狀態,有時候會是接收狀態

第一個數據——(主設備現在處於發生狀態)發送從設備地址,並且把主設備配置爲接收狀態。

第二個數據——(主設備處於接收狀態)ARM9接收數據,注意此時是NO ACK。再停止。(要在產生NO ACK後在讀取數據這時數據會是穩定的。網上有問爲什麼在讀IIC最後需要讀兩次,我自己實驗了,只需要最後一次就行,)

第二種隨機讀數據方式

第一個數據——(主設備處於發生狀態),發送一個從設備地址。第一個設備地址是用來從設備匹配的,也在文檔中被稱爲a “dummy” byte write sequence

第二個數據——(主設備處於發生狀態),發送一個想讀取數據在EEPROM中的地址。

第三個數據——(主設備處於發生狀態),發送一個從設備地址。這是特定要求這樣發送的。。(在這裏主設備會被配置爲接收狀態),這此發送設備地址是用來同時調整主設備狀態的。

第四個數據——(主設備處於接收狀態)需要讀的數據。也是一個NO ACK,與讀當前地址類似。最後再停止。

第三種讀序列地址

與讀當前數據有些類似。

第一個數據——(主設備處於發送狀態),發出設備地址,並配置主設備爲接收狀態。爲後面接收數據準備

第二、三···個數據——(主設備處於接收狀態),前面每個數據都會發送ACK,最後一個數據是一個NO ACK。

再停止。

以上這些,主要要注意主設備狀態的調整,以及爲NO ACK時的處理,後面有事例程序,能夠比較清楚的看到怎麼進行處理的

二:S3C2440中對於IIC需要配置的寄存器

GPECON,主要是把這個GPIO配置爲IIC模式。

IICCON:其中[0]---[3]與[6]共同決定IIC總線的時鐘頻率。

[4]是一箇中斷標誌位,我們如果沒有用中斷方式的話,應該可以通過查詢這一位進行。(我用的中斷,沒有具體自己實踐)

[5]IIC中斷使能。[7]是否發送ACK。這一位在後面讀數據的時候,要注意進行改變。

IICSTAT:這個寄存器主要是一些標誌爲,不需要配置,主要要配置的是這幾位。

[4]使能IIC數據線的,使其能夠發送數據。

[5]啓動和停止IIC,1啓動。0停止。

[6-7]是配置AMR9的狀態的,一般CPU是一個主設備的角色。只有在兩塊CPU進行相互通信的時候,可能把他配置成爲一個從設備的狀態。所以在我們實驗中,ARM9全部都是處於主設備的角色。

IICADD是CPU做從設備的時候,給他配置的從設備地址,這裏可以不用配置。

IICDS:數據移位寄存器。發送數據就是把數據發到這個寄存器。接收數據就是從這個寄存器中去取數據。

如果使用中斷當然還得配置INTMSK,打開IIC中斷。

三:IIC成功讀寫EEPROM的程序

首先要對程序有幾點說明:

1:f_GetACK必須是volatile類型,因爲在中斷中改變了值,不然值被保存在緩存中了,最後檢測時,不能真正讀到其值。詳細見

在C編程中使用到的幾個重要關鍵字之一volatile

2:IIC的中斷總是在ACK週期內,產生的,我沒有貼出操作流程圖,ARM9文檔中IIC這章已經清楚給出。所以在有ACK的那些數據發送與接收都可以用中斷操作,但是從讀數據的後接收數據來看,由於是NO ACK,所以就沒有用中斷操作了,而且自己進行了一個延時。在讀數據。

 

static U8 _iicData[IICBUFSIZE];
static volatile int f_GetACK;



 

void Test_Iic(void)
{
    unsigned int i,j,save_E,save_PE;
    static U8 data[256];

    Uart_Printf("\nIIC Test(Interrupt) using AT24C02\n");

    save_E   = rGPECON;
    save_PE  = rGPEUP;
	IIC_Init();			//初始化IIC必須的一些寄存器
    Uart_Printf("Write test data into AT24C02\n");

    for(i=0;i<48;i++)						
        Wr24C080(0xa0,i,i);			//slvaddr, addr,  data
        												
           
    for(i=0;i<48;i++)
        data[i] = 0;

    Uart_Printf("Read test data from AT24C02\n");
    
    for(i=0;i<48;i++)
        Rd24C080(0xa0,i,&(data[i])); 

        //Line changed 0 ~ f
    for(i=0;i<3;i++)
    {
        for(j=0;j<16;j++)
            Uart_Printf("%2x ",data[i*16+j]);
        Uart_Printf("\n");
    }
    rINTMSK |= BIT_IIC;    
    rGPEUP  = save_PE;
    rGPECON = save_E;
}


 

void IIC_Init(void)
{
	//配置GPE端口爲IIC功能
	rGPECON &=~(0xF<<28);
	rGPECON |=(1<<31)|(1<<29);
//產生ACK,IIC中斷使能,頻率200KHz
	rIICCON = 0;
	rIICCON |=(7)|(1<<5)|(1<<7);
	//模式爲主發送,使能Rx/Tx     (不管是讀還是寫初始化都爲主發送)
	rIICSTAT |=(3<<6)|(1<<4);
	rIICADD = 0x10;//從地址	表示2440作爲從設備的時候的地址,
//在這裏2440是作爲一個主設備存在的,所以沒有作用。
//EEPROM的標識符爲1010
//控制字節,其中高四位爲器件類型標識符,後三位作爲片選 
//最後一位決定讀寫,0是讀,1是寫。

//IIC傳輸中斷開啓
	rINTMOD=0x0;
	rINTMSK &=~BIT_IIC;
	pISR_IIC = (unsigned)IicInt;
}


 

//*************************[ Wr24C080 ]****************************
void Wr24C080(U32 slvAddr,U32 addr,U8 data)
{
    f_GetACK = 0;
	rIICDS = slvAddr;				//發送第一個數據
	rIICSTAT = 0xf0;
	while(f_GetACK == 0);			//等待發送結束
	f_GetACK = 0;
	rIICDS = addr;		   			//發送第二個數據
	rIICCON = 0xaf;
	while(f_GetACK == 0);			//等待發送結束
	f_GetACK = 0;
	rIICDS = data;			    	//發送第三個數據
	rIICCON = 0xaf;
	while(f_GetACK ==0);		   //等待發送結束
	rIICSTAT = 0xd0;			   //停止IIC
	rIICCON = 0xaf;
	Delay(3);
}


 

void Rd24C080(U32 slvAddr,U32 addr,U8 *data)
{
    char cRecvByte;

	f_GetACK = 0;

	rIICDS = slvAddr;	 		//發送第一個數據
	rIICSTAT = 0xf0;
	while(f_GetACK==0);	  		//等待結束
	f_GetACK = 0;
	rIICDS = addr;		 		//發送第二個數據
	rIICCON = 0xAF;
	while(f_GetACK==0);			 //等待結束
	f_GetACK = 0;
	rIICDS = slvAddr;	  		//發送第三個數據
	rIICSTAT = 0xb0;			//配置主設備狀態爲接收
	rIICCON = 0xaf;	  			
	while(f_GetACK==0);			//等待結束
	f_GetACK = 0;
	rIICCON = 0x2f;	  			//NO ACK配置
	Delay(2);				    //等待其穩定,延時不要求精確
	cRecvByte = rIICDS;			//接收第四個數據
	rIICSTAT = 0x90; 			//停止IIC
	rIICCON = 0xaf;
	Delay(3);
	*data = cRecvByte;
}


 

void __irq IicInt(void)
{
	ClearPending(BIT_IIC);    
	f_GetACK = 1;
}


 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章