新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > S3C2440模擬IIC方式操作EEPROM

        S3C2440模擬IIC方式操作EEPROM

        作者: 時間:2016-12-03 來源:網絡 收藏
        先簡單介紹一下基本情況:

        S3C2440下,編寫iic程序,可以有一下三種方法,其實就是2種:

        本文引用地址:http://www.104case.com/article/201612/325195.htm

        1.自己編寫模擬iic程序,控制IO口的變化。

        2.使用驅動本身帶的模擬iic程序,也就是bit-banging。

        3.使用硬件iic,這不在我的討論范圍之內,有時間也可以補充上來。

        我目前使用的是在linux操作系統(tǒng)上實現(xiàn)的代碼:

        貼出實現(xiàn)的代碼(不使用內核中的模擬iic程序):

        第一部分是驅動層的代碼:

        1.EEPROM.c代碼:

        ********************copyright by wit_yuan 2016-09-17 at beijing 龍興園北區(qū)**/
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        #include



        #define SDA_DELAY 5
        #define SCL_DELAY 5

        /*
        *
        * 本函數(shù)是操作在S3C2440上的GPIO模擬IIC程序,不使用內核提供的模擬GPIO操作,也就是不調用:
        * i2c-dev.c,i2c-algo-bit.c,i2c-core.c,i2c-gpio.c文件的內容。
        *
        * 在開發(fā)板上找到兩個引腳,SCL,SDA如下所示:
        * IICSCL GPE14
        * IICSDA GPE15
        *
        */
        /*
        *
        * 操作思路:(具體可以參考STM32的模擬IIC來做)
        * 1.使用基本的文件讀寫操作方法,為應用層提供基本的open,read,write函數(shù)。
        * 2.提供基本的設備注冊,類注冊方法。
        *
        * GPECON:0x56000040 GPE15[31:30] 00-input,01-output 10-IICSDA GPE14[29:28] 10-IICSCL
        * GPEDAT:0x56000044 GPE15[15:0]
        * GPEUP :0x56000048
        *
        *
        */
        struct device *g_p_device;
        struct class *g_p_class;
        static int g_major;
        static volatile unsigned int *GPECON;
        static volatile unsigned int *GPEDAT;

        #define SDA_OUT() do{*GPECON &= ~(0x3 << 30); *GPECON |= (1<<30);} while(0);
        #define SDA_IN() do{*GPECON &= ~(0x3 << 30);} while(0);
        #define READ_SDA ((*GPEDAT)&(1<<15))

        #define SCL_INIT() do{*GPECON &= ~(0x3 << 28); *GPECON |= (1<<28);} while(0);
        #define SDA_INIT() do{*GPECON &= ~(0x3 << 30); *GPECON |= (1<<30);} while(0);


        #define EEPROM_MAGIC m
        #define EEPROM_WRITE _IOW(EEPROM_MAGIC,0,int)
        #define EEPROM_READ _IOR(EEPROM_MAGIC,1,int)

        #define IIC_SDA(a)
        do{
        if(a==0){
        *GPEDAT &= ~(1<<15);
        }
        else
        {
        *GPEDAT |= (1<<15);
        }
        }while(0);

        #define IIC_SCL(a)
        do{
        if(a==0){
        *GPEDAT &= ~(1<<14);
        }
        else
        {
        *GPEDAT |= (1<<14);
        }
        }while(0);

        typedef struct IIC_Struct{
        unsigned char u_device_address;
        unsigned char u_reg_address;

        }T_IIC_Struct;

        static T_IIC_Struct g_t_iic_struct;

        static void IIC_Init(void)
        {
        SCL_INIT();
        SDA_INIT();

        //開啟設置初始狀態(tài)
        IIC_SDA(1);
        udelay(SDA_DELAY);

        IIC_SCL(1);
        udelay(SCL_DELAY);
        }


        /**
        *
        * 這部分是EEPROM的模擬IIC的實現(xiàn)部分。需要仔細
        *
        *
        *
        *
        *
        *
        */
        void IIC_Start(void)
        {
        SDA_OUT();
        IIC_SDA(1);
        udelay(SDA_DELAY);

        IIC_SCL(1);
        udelay(SCL_DELAY);

        IIC_SDA(0);
        udelay(SDA_DELAY);

        IIC_SCL(0);
        udelay(SCL_DELAY);
        }


        void IIC_Stop(void )
        {
        SDA_OUT();

        IIC_SDA(0);
        udelay(SDA_DELAY);

        IIC_SCL(1);
        udelay(SCL_DELAY);

        IIC_SDA(1);
        udelay(SDA_DELAY);
        }

        unsigned char IIC_Wait_Ack(void)
        {
        unsigned short ucErrTime=0;

        IIC_SCL(0);
        udelay(SCL_DELAY);

        SDA_IN(); //SDA設置為輸入

        while(READ_SDA)
        {
        ucErrTime++;
        if(ucErrTime>250)
        {
        IIC_Stop();
        return 1; //超時,表明數(shù)據傳輸有問題
        }
        }
        IIC_SCL(1);
        udelay(SCL_DELAY);

        IIC_SCL(0);//時鐘輸出0
        udelay(SCL_DELAY);

        return 0;
        }

        //產生ACK應答
        void IIC_Ack(void)
        {
        IIC_SCL(0);
        udelay(SCL_DELAY);

        //added by wit_yuan 2016-09-16
        SDA_OUT();
        IIC_SDA(1);
        udelay(SDA_DELAY);


        IIC_SDA(0);
        udelay(SDA_DELAY);


        IIC_SCL(1);
        udelay(SCL_DELAY);
        IIC_SCL(0);
        udelay(SCL_DELAY);

        //////add 2016-09-16 by wit_yuan///////////
        IIC_SDA(1);
        udelay(SDA_DELAY);
        }

        //不產生ACK應答
        void IIC_NAck(void)
        {
        SDA_OUT();
        IIC_SCL(0);
        udelay(SCL_DELAY);

        IIC_SDA(1);
        udelay(SDA_DELAY);

        IIC_SCL(1);
        udelay(SCL_DELAY);
        IIC_SCL(0);
        udelay(SCL_DELAY);
        }

        void IIC_Send_Byte(unsigned char txd)
        {
        unsigned char t;
        SDA_OUT();
        IIC_SCL(0);//拉低時鐘開始數(shù)據傳輸
        udelay(SCL_DELAY);
        for(t=0;t<8;t++)
        {
        if((txd&0x80)>>7)
        {
        IIC_SDA(1);
        }
        else
        {
        IIC_SDA(0);
        }
        txd<<=1;
        udelay(SDA_DELAY);
        IIC_SCL(1);
        udelay(SCL_DELAY);
        IIC_SCL(0);
        udelay(SCL_DELAY);
        }
        }

        //讀1個字節(jié),ack=1時,發(fā)送ACK,ack=0,發(fā)送nACK
        unsigned char IIC_Read_Byte( void )
        {
        unsigned char i,u_receive=0;
        SDA_IN();//SDA設置為輸入
        for(i=0;i<8;i++ )
        {
        IIC_SCL(0);
        udelay(SCL_DELAY);
        IIC_SCL(1);
        udelay(SCL_DELAY);
        u_receive<<=1;
        if(READ_SDA)
        u_receive++;
        }

        return u_receive;
        }


        ssize_t EEPROM_Write(struct file *p_file, const char __user *p_buf, size_t len, loff_t *p_lof)
        {


        unsigned int i;
        unsigned int i_err = 0;

        unsigned char *p_buffer;


        if(len <= 0)
        return 0;

        p_buffer = kzalloc(sizeof(char) * len, GFP_KERNEL);
        copy_from_user(p_buffer,p_buf,len);

        printk("----EEPROM write device-----n");

        IIC_Start();
        IIC_Send_Byte(g_t_iic_struct.u_device_address << 1);
        i_err |= IIC_Wait_Ack();

        IIC_Send_Byte(g_t_iic_struct.u_reg_address);
        i_err |= IIC_Wait_Ack();

        for( i = 0 ; i < len ; i ++ )
        {
        IIC_Send_Byte(p_buffer[i]);

        i_err |= IIC_Wait_Ack();
        }
        IIC_Stop();

        kfree(p_buffer);

        if(i_err == 0)
        return 0;

        return 1;
        }

        ssize_t EEPROM_Read(struct file *p_file, char __user *p_buf, size_t len, loff_t *p_lof)
        {
        int i = 0;
        printk("----EEPROM read device-----n");


        unsigned char u_temp;
        unsigned char u_wait_err = 0;

        unsigned char *p_buffer;
        p_buffer = kzalloc(sizeof(char) * len, GFP_KERNEL);

        if(len <= 0)
        return 0;

        IIC_Start();
        IIC_Send_Byte(g_t_iic_struct.u_device_address << 1);
        u_wait_err |= IIC_Wait_Ack();

        IIC_Send_Byte(g_t_iic_struct.u_reg_address);
        u_wait_err |= IIC_Wait_Ack();

        IIC_Start();
        IIC_Send_Byte((g_t_iic_struct.u_device_address << 1)+1);
        u_wait_err |= IIC_Wait_Ack();

        for(i = 0 ; i < len - 1 ; i ++)
        {
        //p_buffer[i] = IIC_Read_Byte( );
        *p_buffer = IIC_Read_Byte( );
        IIC_Ack();
        p_buffer ++;
        }
        //p_buffer[len-1] = IIC_Read_Byte( );
        *p_buffer = IIC_Read_Byte( );

        IIC_NAck();//不需要響應

        IIC_Stop();

        #if 0
        printk("read data is 0x%0xn",u_temp);
        printk("error status:%dn",u_wait_err);
        #endif

        copy_to_user(p_buf,p_buffer - len + 1,len);

        #if 0
        printk("kernel array : n");
        for(i = 0 ; i < len ; i ++)
        printk("0x%0x n",p_buf[i]);
        printk("n");
        #endif

        kfree(p_buffer);

        if(u_wait_err == 0)
        return 0;
        return 1;
        }


        int EEPROM_Open(struct inode *p_inode, struct file *p_file)
        {
        printk("----EEPROM open device-----n");

        //本句是將GPIO初始化。
        IIC_Init();

        return 0;
        }


        /*
        *
        * 規(guī)定:
        * 在IOCTL中接收應用層傳過來的基本控制命令,包括i2c設備的地址,寄存器地址等。
        * 在write,read函數(shù)中,才可以寫入buffer.
        *
        */
        long EEPROM_Ioctl (struct file *p_file, unsigned int cmd, unsigned long args)
        {
        switch(cmd)
        {
        case EEPROM_WRITE:
        printk("----ioctl write---n");

        copy_from_user(&g_t_iic_struct,(T_IIC_Struct *)args,4);

        printk("u_device_address=0x%0xn",g_t_iic_struct.u_device_address);
        printk("u_reg_address=0x%0xn",g_t_iic_struct.u_reg_address);

        break;
        case EEPROM_READ:
        printk("----ioctl read---n");

        copy_to_user((T_IIC_Struct *)args,&g_t_iic_struct,4);
        printk("u_device_address=0x%0xn",g_t_iic_struct.u_device_address);
        printk("u_reg_address=0x%0xn",g_t_iic_struct.u_reg_address);

        break;
        }
        return 0;
        }


        static const struct file_operations EEPROM_File_Ops = {
        .owner = THIS_MODULE,
        .open = EEPROM_Open,
        .read = EEPROM_Read,
        .write = EEPROM_Write,
        .unlocked_ioctl = EEPROM_Ioctl,

        };

        static int __init EEPROM_init(void)
        {
        int ret;
        printk("-----EEPROM Init---------n");

        g_major = register_chrdev(0,"EEPROM_Chrdev",&EEPROM_File_Ops);
        g_p_class = class_create(THIS_MODULE, "EEPROM");
        g_p_device = device_create(g_p_class, NULL,MKDEV(g_major, 0), NULL,
        "i2c-%d", 1);

        GPECON = ioremap(0x56000040,4);
        GPEDAT = ioremap(0x56000044,4);

        return ret;
        }



        static void __exit EEPROM_exit(void)
        {
        printk("-----EEPROM Exit---------n");

        iounmap(GPECON);
        iounmap(GPEDAT);

        device_destroy(g_p_class,MKDEV(g_major, 0));
        class_destroy(g_p_class);
        unregister_chrdev(g_major,"EEPROM_Chrdev");

        }

        module_init(EEPROM_init);
        module_exit(EEPROM_exit);



        MODULE_AUTHOR("wit_yuan");
        MODULE_DESCRIPTION("I2C-EEPROM by wit_yuan 2016-09-17 at beijing");
        MODULE_LICENSE("GPL");

        /*************end of file for EEPROM driver*****************************/


        2.EEPROM.h文件:

        #ifndef _EEPROM_H_
        #define _EEPROM_H_







        #endif


        第二部分是Makefile文件內容:

        obj-m:=EEPROM.o

        KERNEL_DIR:= /home/wityuan/Downloads/linux-3.12.57

        PWD:=$(shell pwd)

        all:
        make -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules

        clean:
        rm *.o *.ko *.mod.clean


        第三部分是應用層的測試程序EEPROM_App.c文件:

        #include
        #include
        #include
        #include
        #include
        #include


        #define EEPROM_MAGIC m
        #define EEPROM_WRITE _IOW(EEPROM_MAGIC,0,int)
        #define EEPROM_READ _IOR(EEPROM_MAGIC,1,int)

        typedef struct IIC_Struct{
        unsigned char u_device_address;
        unsigned char u_reg_address;

        }T_IIC_Struct;

        static T_IIC_Struct g_t_iic_struct;




        int main(int argc,char *argv[])
        {
        int i_fd;
        int i = 0;
        unsigned char u_array_buf[10];

        unsigned char u_array_write_buffer[10];

        i_fd = open("/dev/i2c-1",O_RDWR);

        if(i_fd < 0)
        {
        printf("open device errorn");
        return -1;
        }

        printf("----open device ok----n");

        g_t_iic_struct.u_device_address = 0x50;
        g_t_iic_struct.u_reg_address = 0x0;

        //初始化寫數(shù)據的數(shù)組
        for(i = 0 ; i < 10 ; i ++)
        u_array_write_buffer[i] = i + 1;


        ioctl(i_fd,EEPROM_WRITE,&g_t_iic_struct);

        //寫數(shù)據內容
        write(i_fd,u_array_write_buffer,10);

        //讀取EEPROM的數(shù)據

        read(i_fd,u_array_buf,10);


        printf("nread :n");
        for(i = 0; i < 10 ; i ++)
        printf("0x%0x ",u_array_buf[i]);

        printf("n");

        while(1);

        return 0;
        }


        代碼結束了,具體的iic協(xié)議解釋性內容,還是一樣,參考stm32的模擬iic操作EEPROM吧。

        這次,貼出一個實現(xiàn)效果圖:

        好了,這就是本節(jié)的內容了。



        關鍵詞: S3C2440模擬IICEEPRO

        評論


        技術專區(qū)

        關閉
        主站蜘蛛池模板: 自贡市| 枞阳县| 六盘水市| 海阳市| 建始县| 宁德市| 广元市| 扎赉特旗| 全州县| 榆林市| 土默特左旗| 务川| 永和县| 锡林郭勒盟| 宁阳县| 益阳市| 康定县| 高要市| 南江县| 六枝特区| 宣恩县| 兴安盟| 苗栗市| 博湖县| 威远县| 靖宇县| 读书| 曲阜市| 泰来县| 崇信县| 阿拉善左旗| 华阴市| 青州市| 琼结县| 抚顺县| 许昌市| 青川县| 洱源县| 遵义县| 西吉县| 布尔津县|