S3C2440模擬IIC方式操作EEPROM
在S3C2440下,編寫(xiě)iic程序,可以有一下三種方法,其實(shí)就是2種:
本文引用地址:http://m.butianyuan.cn/article/201612/325195.htm1.自己編寫(xiě)模擬iic程序,控制IO口的變化。
2.使用驅(qū)動(dòng)本身帶的模擬iic程序,也就是bit-banging。
3.使用硬件iic,這不在我的討論范圍之內(nèi),有時(shí)間也可以補(bǔ)充上來(lái)。
我目前使用的是在linux操作系統(tǒng)上實(shí)現(xiàn)的代碼:
貼出實(shí)現(xiàn)的代碼(不使用內(nèi)核中的模擬iic程序):
第一部分是驅(qū)動(dòng)層的代碼:
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程序,不使用內(nèi)核提供的模擬GPIO操作,也就是不調(diào)用:
* i2c-dev.c,i2c-algo-bit.c,i2c-core.c,i2c-gpio.c文件的內(nèi)容。
*
* 在開(kāi)發(fā)板上找到兩個(gè)引腳,SCL,SDA如下所示:
* IICSCL GPE14
* IICSDA GPE15
*
*/
/*
*
* 操作思路:(具體可以參考STM32的模擬IIC來(lái)做)
* 1.使用基本的文件讀寫(xiě)操作方法,為應(yīng)用層提供基本的open,read,write函數(shù)。
* 2.提供基本的設(shè)備注冊(cè),類注冊(cè)方法。
*
* 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();
//開(kāi)啟設(shè)置初始狀態(tài)
IIC_SDA(1);
udelay(SDA_DELAY);
IIC_SCL(1);
udelay(SCL_DELAY);
}
/**
*
* 這部分是EEPROM的模擬IIC的實(shí)現(xiàn)部分。需要仔細(xì)
*
*
*
*
*
*
*/
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設(shè)置為輸入
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1; //超時(shí),表明數(shù)據(jù)傳輸有問(wèn)題
}
}
IIC_SCL(1);
udelay(SCL_DELAY);
IIC_SCL(0);//時(shí)鐘輸出0
udelay(SCL_DELAY);
return 0;
}
//產(chǎn)生ACK應(yīng)答
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);
}
//不產(chǎn)生ACK應(yīng)答
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í)鐘開(kāi)始數(shù)據(jù)傳輸
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個(gè)字節(jié),ack=1時(shí),發(fā)送ACK,ack=0,發(fā)送nACK
unsigned char IIC_Read_Byte( void )
{
unsigned char i,u_receive=0;
SDA_IN();//SDA設(shè)置為輸入
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();//不需要響應(yīng)
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中接收應(yīng)用層傳過(guò)來(lái)的基本控制命令,包括i2c設(shè)備的地址,寄存器地址等。
* 在write,read函數(shù)中,才可以寫(xiě)入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文件內(nèi)容:
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
第三部分是應(yīng)用層的測(cè)試程序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;
//初始化寫(xiě)數(shù)據(jù)的數(shù)組
for(i = 0 ; i < 10 ; i ++)
u_array_write_buffer[i] = i + 1;
ioctl(i_fd,EEPROM_WRITE,&g_t_iic_struct);
//寫(xiě)數(shù)據(jù)內(nèi)容
write(i_fd,u_array_write_buffer,10);
//讀取EEPROM的數(shù)據(jù)
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;
}
代碼結(jié)束了,具體的iic協(xié)議解釋性內(nèi)容,還是一樣,參考stm32的模擬iic操作EEPROM吧。
這次,貼出一個(gè)實(shí)現(xiàn)效果圖:
好了,這就是本節(jié)的內(nèi)容了。
評(píng)論