Use IIC bus to read and write i2c slave device register under Linux
by Han David @Jilin Normal University
handawei@jusontech.com
Reprint please be sure to indicate the source
******************* ******************************* ***************
2012.7.16
1. This article gives the implementation program of reading and writing i2c slave device using IIC bus under linux.
2. This article gives solutions to several very subtle errors encountered in programming.
3. The reading and writing program in this article is very general:
i2c -d / dev / i2c-1 -s 0x51 0x05 18 ----- Write 18 to the register: 0x05 of the i2c-slave address: 0x51
i2c -d / dev / i2c-10 0x57 0x05 ------ Read the register: 0x05 of the i2c-slave address: 0x57
i2c 0x40 0x0f ----- read in the default path i2c slave device address 0x40 0x0f address (or register address)
4. This program takes the EEPROM as an example, and finally shows how to read and write the general program of the slave device under i2c, not for the EEPROM chip. There is also an article in "Communication with E2PROM under Linux using i2c bus"
Some operations of EEPROM. But the principle is the same as this article.
The E2PROM in our embedded system is 24C02. Let ’s briefly understand this chip:
The storage capacity of AT24C02 is 2Kb, the content is divided into 32 pages, each page 8B, a total of 256B, there are two addressing modes during operation: chip addressing and on-chip sub-address addressing.
(1) Chip addressing: The chip address of AT24C02 is 1010, and the address control word format is 1010A2A1A0R / W. Among them A2, A1, A0 programmable address selection bits. A2, A1, A0 pins are connected high,
After the low level, the determined three-bit code is formed, and the 7-bit code is formed with 1010, which is the address code of the device. R / W is the chip read-write control bit, this bit is 0, indicating that the chip performs a write operation.
(2) On-chip sub-address addressing: chip addressing can read / write any of the internal 256B, and its addressing range is 00 ~ FF, a total of 256 addressing units.
We use the second addressing method.
In addition, there is a question that needs to be understood, that is, EEPROM and flash, when to use EEPROM, when to use FLASH is appropriate.
********************
From Www.baidu.com:
Flash memory, also known as flash memory, combines the advantages of ROM and RAM, not only has the performance of electronically erasable and programmable (EEPROM), but also can quickly read data (NVRAM advantage), so that the data will not be powered off
Lost. This kind of memory is used in U disk and MP3. Used to store Bootloader and operating system or program code, or directly used as a hard disk (U disk).
One, EEPROM reads and writes with single byte, some chips of FLASH can only be erased in block mode (whole chip erase), some chips can be written (programmed) in single byte, generally block write mode is needed;
Second, FLASH has faster read and write speeds and higher reliability than EEPROM.
Third, in terms of price, FLASH is more expensive than EEPROM.
So, our version card parameter information, wait for some fixed, small amount, do not need to modify the data information frequently in the EEPROM. The flash is used as a memory for storing programs, storing operating system codes, etc. that need to be read and written quickly,
Frequently accessed data.
This statement returned the error message bad address.
After checking the information, the very cause of the error is concealed and very simple:
The definition of copy_to_user is:
copy_to_user (void __user * to, const void * from, unsigned long n);
But this unsigned long is equal to unsigned int on a 32bit processor, both are 4 bytes, 32bit.
So I initially had this definition in eeprom_io.h: typedef unsigned long u32;
In eeprom_io.c: ioctl (fd, I2C_RDWR, (u32) iocs);
The processor of our version card is a 64bit mips series processor, unsigned long is 8 bytes, 64bit. The cross compiler will not report an error. But after running, there will always be Bad address due to the problem of bytes
Error feedback. This misleads me simply to think that the address is wrong.
Later I changed typedef unsigned long u32 to typedef unsigned long u64;
ioctl (fd, I2C_RDWR, (u64) iocs). Only to solve this problem.
The first write execution was successful, which means that there is no problem with the code. Then the second execution fails. There should be other reasons. I checked the 24C02 information on the Internet. It turned out that it was like this:
"After the data is written, it must be delayed by 10MS after giving a stop signal. It takes 24C02 so long to load the data"
This is the electrical characteristic of 24C02.
Use usleep (10000) once in the write function.
To add: Our CPU is a 6 core 500M frequency, and its computing power is extremely strong. If you write a general delay at the user level
The program does not work at all. Generally, two fors are used, and one for is executed 10,000 times. There will be a significant delay on the PC. but
In our embedded system, 8 for statements are used, and each for is executed 10,000 times, with no impact at all
A slight delay. In addition, simply using the for action delay will block the CPU at full load,
Affect other functions, so it is recommended that you use the usleep () function, usleep (10000), which is exactly 10Ms, so
The best use of CPU time.
int i_open (unsigned char * dev, unsigned int timeout, unsigned int retry) {
return i2c_open (dev, timeout, retry);
}
int read_data (u16 addr, u8 offset, u8 * val) {
int ret;
The
ret = i2c_read_data (addr, offset, val);
if (ret <0) {
printf ("% s error! \ n", __ FUNCTION__);
exit (-1);
}
printf ("read success, val =% 02x \ n", * val);
return 0;
}
int write_data (u16 addr, u8 offset, char * argv) {
The
int ret;
u8 val = (unsigned char) strtoul (argv, 0,16);
The
ret = i2c_write_data (addr, offset, val);
if (ret <0) {
printf ("% s error! \ n", __ FUNCTION__);
exit (-1);
}
printf ("write success, val =% 02x \ n", val);
usleep (10000); // Delay program
return 0;
}
int help_info (void) {
printf ("\ nUsage: i2c [-d PATH] ADDR OFFSET \ n");
printf ("\ nOr: i2c [-d PATH] -s ADDR OFFSET DATA \ n");
printf ("\ nRead or Write the register of i2c slave \ n");
printf ("\ nFor example \ n");
printf ("\ ti2c 0x51 0x05 \ t \ t \ t \ t \ t \ tRead the register: 0x05 of the address: 0x51 \ n");
printf ("\ ti2c -d / dev / i2c-10 0x51 0x05 \ t \ t \ t \ tRead the register: 0x05 of the address: 0x51 \ n");
printf ("\ ti2c -d / dev / i2c-1 -s 0x51 0x05 18 \ t \ t \ tWrite 18 to the register: 0x05 of the address: 0x51 \ n \ n");
int
i2c_open (unsigned char * dev, unsigned int timeout, unsigned int retry)
{
if ((fd = open (dev, O_RDWR)) <0)
return fd;
The
__i2c_set (fd, timeout, retry);
return fd;
}
static int
__i2c_send (int fd, struct i2c_rdwr_ioctl_data * data)
{
if (fd <0)
return -1;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef short s16;
typedef int s32;
typedef long long s64;
unsigned bcd2bin (unsigned char val);
unsigned bcd2bin (unsigned char val);
static int
__i2c_send (int fd, struct i2c_rdwr_ioctl_data * data);
static int
__i2c_set (int fd, unsigned int timeout, unsigned int retry);
int
i2c_read_data (u16 addr, u8 offset, u8 * val);
int
i2c_write_data (u16 addr, u8 offset, u8 val);
int
i2c_open (unsigned char * dev, unsigned int timeout, unsigned int retry);
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.