[Creación del 1 de mayo] Linux --- Programación de aplicaciones I2C

Tabla de contenido

Prefacio:

1. Protocolo I2C

(1. Información general

(2) Marco de hardware I2C:

(3) marco de software I2C

(4) formato de datos I2C

2. Protocolo SMBus

Tres, la estructura importante del sistema I2C

4. Acceso al dispositivo I2C (AP3216C)

(1) Usando el protocolo SMBus:​​​​

 (2) Utilice el protocolo I2C:

 (3) Análisis de código fuente de I2C-Tools:

5. Escriba la aplicación para acceder a EEPROM (AT24C02)

(1) método de acceso AT24C02

1. Dirección del dispositivo

2. Escribir datos

3. Leer datos

(2) Programación con herramientas I2C

1. Ejemplo específico: (SMBus)

2. Compilación, efecto real


Prefacio:

Enlace clásico: pensar y practicar con preguntas

(1) protocolo I2C

  • ¿Qué es I2C? ¿Cuáles son las características?
  • ¿Cuál es el proceso específico de transmisión de datos I2C?
  • ¿Cómo genera I2C la señal de inicio (S), la señal final (P), la señal de respuesta (ACK) y envía datos?
  • I2C es transmisión bidireccional, entonces, ¿cómo realizar la transmisión bidireccional en SDA?

(2) protocolo SMBus

  • ¿Qué es el protocolo SMBus?
  • ¿Cuáles son las similitudes y diferencias entre él y I2C?

(3) Implementación de I2C en Linux

  • En Linux, ¿cómo representar el controlador I2C, el dispositivo I2C y los datos que se transmitirán?

(4) práctica de programación de aplicaciones I2C

  • AP3216C
  • EEPROM-AT24C02

El contenido del siguiente artículo responderá a las preguntas anteriores en detalle. Si te ayuda, por favor apóyame y dame más motivación para crear.

1. Protocolo I2C

(1. Información general

¿Qué es I2C? ¿Cuáles son las características?

En electrónica de consumo, electrónica industrial y otros campos, se utilizan varios tipos de chips, como microcontroladores, administración de energía, controladores de pantalla, sensores, memorias, convertidores, etc., tienen diferentes funciones y, en ocasiones, requieren una interacción rápida de datos, para poder Para utilizar la forma más sencilla de interconectar estos chips, nació I2C I2C ( Inter-Integrated Circuit ) es un protocolo de bus general. Es un estándar de protocolo de bus de dos hilos bidireccional simple desarrollado por Philips (Philips), ahora NXP (NXP) Semiconductor .

Para los diseñadores de hardware, solo se necesitan 2 pines, muy pocas líneas y áreas de conexión para realizar la comunicación entre los chips.Para los desarrolladores de software, se puede usar la misma biblioteca de controladores I2C para realizar la realización de diferentes dispositivos.El controlador reduce en gran medida el desarrollo de software. tiempo. La corriente de trabajo extremadamente baja reduce el consumo de energía del sistema y el mecanismo de respuesta perfecto mejora en gran medida la confiabilidad de la comunicación.

Las características son las siguientes:

  • I2C es semidúplex
  • I2C admite el modo multimaestro y multiesclavo
  • Desde la perspectiva de la ocupación de GPIO, I2C ocupa dos GPIO
  • I2C tiene un mecanismo de respuesta y la confiabilidad de los datos es mayor
  • La tasa I2C no será demasiado alta, la tasa máxima es de 3,4 Mbps
  • I2C selecciona el esclavo a través de la dirección del dispositivo, y el aumento en la cantidad de esclavos no conducirá a un aumento en GPIO
  • I2C realiza muestreo de datos en el dispositivo de alto nivel SCL.
  • La mayoría de ellos se utilizan en la comunicación de corta distancia de los dispositivos de a bordo.

(2) Marco de hardware I2C:

  • Dentro de un chip (Soc), hay uno o más controladores I2C.
  • En un controlador I2C, se pueden conectar uno o más dispositivos I2C. --- Debe saber la dirección
  • El bus I2C solo necesita dos líneas: la línea de reloj SCL y la línea de datos SDA.
  • Hay resistencias pull-up en las líneas SCL y SDA del bus I2C.

(3) marco de software I2C

En Linux, la aplicación accede al dispositivo I2C a través del controlador del dispositivo I2C para analizar los datos y el controlador del controlador I2C para enviar y recibir datos.

Tome el dispositivo de almacenamiento AT24C02 con interfaz I2C como ejemplo:

  • APLICACIÓN:
    • Haz una solicitud: escribe la cadena "¡hola mundo!" al principio de la dirección 16 de AT24C02
    • No le importan los detalles de la implementación subyacente, solo necesita llamar a la interfaz proporcionada por el controlador del dispositivo
  • Controlador AT24C02:
    • Conoce la dirección y el formato de datos requerido por AT24C02
    • Sabe qué señal enviar para que el AT24C02 realice trabajos de borrado y programación
    • Sabe cómo juzgar si los datos están programados con éxito, construye una serie de datos y los envía al controlador I2C.
  • Controlador de controlador I2C
    • Envía varias señales según el protocolo I2C: dirección de dispositivo I2C, dirección de almacenamiento I2C, datos
    • Juzga según el protocolo I2C

(4) formato de datos I2C

¿Cuál es el proceso específico de transmisión de datos I2C?

Tome la operación de escritura como un ejemplo: 

  • El chip principal necesita enviar una señal de inicio
  • Luego envíe una dirección de dispositivo (usada para determinar si el dispositivo existe) y luego podrá transmitir datos
  • El dispositivo maestro envía un byte de datos al dispositivo esclavo y espera una respuesta
  • Cada vez que se transmite un byte de datos, el receptor necesita una señal de respuesta (determina si se aceptan los datos) y luego transmite los siguientes datos
  • Después de enviar los datos, el chip principal enviará una señal de parada.

¿Cómo genera I2C la señal de inicio (S), la señal final (P), la señal de respuesta (ACK) y envía datos?

Como se muestra abajo:

  • Señal de inicio: SDA es alto a bajo, y cuando SCL permanece alto, se genera una señal de inicio (S)
  • Señal final: SCL permanece alto, SDA va de bajo a alto y se genera una señal final (P)
  • Señal de respuesta: después de que el receptor reciba datos de 8 bits, bajará SDA en el noveno ciclo de reloj para generar una señal de respuesta (ACK)

Hay dos puntos centrales de transmisión de datos específicos, como se muestra en la siguiente figura:

  • Cuando SCL es alto, los datos SDA deben permanecer estables.
  • Cuando SCL es bajo, SDA puede cambiar (SDA alto (1), bajo (0)).
  • En este momento, cuando SCL esté en un nivel alto, consulte el nivel en SDA para obtener datos.

De lo anterior podemos ver que I2C es una transmisión bidireccional, entonces, ¿cómo realizar la transmisión bidireccional en SDA?

  1. De acuerdo con la situación anterior, hay dos controladores (dispositivo maestro y dispositivo esclavo), si están conectados directamente, si hay una falla, uno emite un nivel alto y el otro un nivel bajo, y el circuito se cortocircuitará.
  2. Cuando uno de los dos dispositivos envía datos, ¿cómo puede el otro no afectar los datos en SDA?

Aquí se utiliza un tubo triodo o CMOS para regular y prevenir este problema. Los ejemplos son los siguientes:

La tabla de verdad correspondiente al circuito anterior es la siguiente:

 De la tabla de verdad y el circuito sabemos:

  • Cuando un cierto chip no quiere afectar la línea SDA, no maneja el triodo
  • Si desea que SDA emita un nivel alto, ninguno de los lados impulsará el triodo
  • Si desea que SDA emita un nivel bajo, conduzca el triodo

En tal caso, la transmisión de datos puede implementarse así:

  • Durante los primeros 8 ciclos, el dispositivo esclavo no controla el triodo y el dispositivo maestro determina los datos; no controla cuando envía 1 y controla el triodo cuando envía 0.
  • En el noveno clk, el dispositivo maestro no maneja el triodo, y el dispositivo esclavo determina los datos; en respuesta a la señal, maneja el triodo para hacer SDA 0.

 Nota: ¿Por qué usar una resistencia pull-up?

Después del noveno reloj, si una de las partes necesita más tiempo para procesar los datos, puede hacer que el transistor baje el SCL.

2. Protocolo SMBus

SMBus: Bus de gestión del sistema, bus de gestión del sistema.

SMBus se basa en el protocolo I2C, que tiene requisitos más estrictos y es un subconjunto del protocolo I2C. Se utiliza para conectar varios dispositivos, incluidos dispositivos relacionados con la alimentación, sensores del sistema, dispositivos de comunicación EEPROM y más.

¿Cuáles son los requisitos más estrictos para SMBus? ¿Cuál es la diferencia con el protocolo I2C general?

  • El valor límite de VDD es diferente

    • Protocolo I2C: amplio rango, incluso hasta 12V discutido

    • SMBus: 1,8 V ~ 5 V

  • Frecuencia de reloj mínima, estiramiento de reloj máximo (cuando un dispositivo necesita más tiempo para el procesamiento interno, puede bajar SCL para ocupar el bus I2C)

    • I2C: no hay límite para la frecuencia de reloj mínima, y ​​no hay límite para la duración de Clock Stretching

    • SMBus: la frecuencia de reloj mínima es de 10 KHz, y el valor de tiempo máximo de Clock Stretching también está limitado

  • Reconocimiento de dirección: después de que un dispositivo I2C recibe su dirección de dispositivo, ¿debe enviar una señal de reconocimiento?

    • Protocolo I2C: no hay ningún requisito obligatorio para enviar una señal de respuesta

    • SMBus: Es obligatorio enviar una señal de respuesta para que la otra parte sepa el estado del dispositivo: ocupado, fallado o eliminado

  • El protocolo SMBus especifica el formato de transmisión de datos

    • Protocolo I2C: solo define cómo transmitir datos, pero no define el formato de los datos, que está completamente definido por el dispositivo

    • SMBus: Se definen varios formatos de datos

  • Condición de INICIO REPETIDO (señal S repetida) --- SMBus

    • Entre la escritura y la lectura, la señal P puede no enviarse, pero la señal S se envía directamente: esta señal S es INICIO REPETIDO.

Análisis del protocolo SMBus, su contenido específico:

Símbolos SMBus (símbolos): 

Agrega código de comando (byte de comando, generalmente indica la dirección de registro dentro del chip), conteo de bytes (longitud de datos), byte de datos (byte de datos, admite 8 bits, 16 bits) y código de verificación PEC en base al protocolo I2C mecanismo. 

Tome SMBus Block Read (complejo) como ejemplo:

  • Función en herramientas I2C: i2c_smbus_read_block_data().

  • Primero emita el código de comando (comprensión y análisis: la dirección es la dirección del dispositivo esclavo y el código de comando es generalmente la dirección del registro dentro del chip)
  • reiniciar la operación de lectura
    • Primero lee un byte (Recuento de bloques), indicando el número de bytes que se leerán más tarde
    • Luego lee todos los datos

Para obtener más información sobre los formatos de datos, consulte los siguientes artículos: 

Protocolo SMBus impulsado por Linux system_i2c_smbus_read_byte_data_Wei Dongshan's blog-CSDN blog

注:在很多设备都实现了 SMBus,而不是更宽泛的 I2C 协议,所以优先使用SMBus。
即使 I2C 控制器没有实现 SMBus,软件方面也是可以使用 I2C 协议来模拟 SMBus。
所以: Linux 建议优先使用 SMBus。

Tres, la estructura importante del sistema I2C

Desde el marco de hardware de la primera pieza de contenido I2C, la transmisión I2C se centra en el controlador I2C, el dispositivo I2C y los datos transmitidos.

¿Cómo representar el controlador I2C? 

  • Es el número de controlador I2C        
  • ¿Cómo envía y recibe datos el controlador I2C?

Aquí el controlador I2C está representado por i2c_adapter, y la estructura correspondiente es la siguiente: 

  • nr indica el número de controlador I2C
  • i2c_algorithm, que contiene la función de transferencia del BUS I2C, utilizado para enviar y recibir datos I2C 

 ¿Cómo representar el dispositivo I2C?

  • Debe tener la dirección del dispositivo
  • ¿En qué controlador I2C está montado --- cuál es el adaptador I2C correspondiente?

 Aquí el dispositivo I2C está representado por i2c_client, y la estructura correspondiente es la siguiente:

  • addr: dirección del dispositivo
  • adaptador: a qué controlador I2C corresponde

 ¿Cómo representar los datos a transferir?

 Aquí los datos están representados por i2c_msg:

  • Los indicadores en i2c_msg se utilizan para indicar la dirección de transmisión: el bit 0 es igual a I2C_M_RD para lectura, el bit 0 es igual a 0 para escritura

  • Ejemplo: Para la EEPROM cuya dirección de dispositivo es 0x50, para leer un byte almacenado en ella con dirección 0x10, se deben construir dos i2c_msg

    • El primer i2c_msg indica una operación de escritura y envía la dirección de almacenamiento 0x10 para acceder al dispositivo.
    • El segundo i2c_msg indica una operación de lectura.
  • Centrarse en addr (dirección), flags (dirección), len (longitud), buf (datos)

4. Acceso al dispositivo I2C (AP3216C)

La aplicación necesita un controlador para acceder al hardware. Para dispositivos I2C, puede llamar al controlador drivers/i2c/i2c-dev.c proporcionado por el kernel. A través de él, puede usar directamente el controlador del adaptador en el controlador del controlador I2C para acceder al dispositivo I2C (AP3216C). 

AP3216C es un sensor tres en uno de infrarrojos, intensidad de luz y distancia.Tomando como ejemplo la lectura de intensidad de luz y distancia, los pasos son los siguientes:

  • Restablecer: escriba 0x4 para registrar 0
  • Habilitar: escribir 0x3 para registrar 0
  • Leer intensidad de luz: leer registro 0xC, 0xD para obtener 2 bytes de intensidad de luz
  • Distancia de lectura: lea el registro 0xE, 0xF para obtener el valor de distancia de 2 bytes 

Aquí puede usar I2C-Tools para operar el sensor AP3212C, hay dos formas (SMBus e I2C) para acceder al dispositivo:

(1) Usando el protocolo SMBus:​​​​

i2cset和i2cget函数用法,后面依次为:
命令(-f、-y)
I2CBUS(0)
设备地址
寄存器地址
数据data

 (2) Utilice el protocolo I2C:

i2ctransfer函数用法,后面依次为:
命令(-f、-y)
I2CBUS(0)
描述符(读写w1/w2 + @设备地址 )
寄存器地址
数据data

 (3) Análisis de código fuente de I2C-Tools:

En combinación con el análisis del proceso anterior, los pasos específicos del proceso:

  • Abrir el nodo /dev/i2c-0 (abierto) accederá a los dispositivos bajo el controlador I2C. (Nota: i2c-dev.c genera un nodo de dispositivo para cada controlador I2C (bus I2C, adaptador I2C): /dev/i2c-0, /dev/i2c-1, etc.;)
  • Especifica la dirección del dispositivo I2C (opcional: ioctl(archivo, I2C_SLAVE, dirección), obligatorio: ioctl(archivo, I2C_SLAVE_FORCE, dirección) )
  • Luego use el formato de datos SMBus correspondiente y use la función ioctl(file, I2C_SMBUS, &args) para transferir datos.

5. Escriba la aplicación para acceder a EEPROM (AT24C02)

(1) método de acceso AT24C02

1. Dirección del dispositivo

 Según la hoja de datos y el hardware A2A1A0 está conectado a tierra, la dirección del dispositivo AT24C02 es 0b1010000, que es 0x50.

2. Escribir datos

El tiempo de datos aquí es:

  • bit de inicio + dirección del dispositivo + escritura + bit correspondiente
  • Registrar dirección + datos 

3. Leer datos

Se puede leer un byte o varios bytes de forma continua. Cuando hay múltiples bytes consecutivos, la dirección dentro del chip se acumulará automáticamente. Cuando la dirección alcance la última dirección del espacio de almacenamiento, comenzará desde 0. Como se muestra abajo:

(2) Programación con herramientas I2C

1. Ejemplo específico: (SMBus)

#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include "i2cbusses.h"
#include <time.h>


/* ./at24c02 <i2c_bus_number> w "100ask.taobao.com"
 * ./at24c02 <i2c_bus_number> r
 */

int main(int argc, char **argv)
{
	unsigned char dev_addr = 0x50;
	unsigned char mem_addr = 0;
	unsigned char buf[32];

	int file;
	char filename[20];
	unsigned char *str;

	int ret;

	struct timespec req;
	
	if(argc != 3 && argc != 4)
	{
		printf("Usage:\n");
		printf("%Write EEprom: %s /dev/i2c-0|1|2 w str\n", argv[0]);
		printf("%Read  EEprom: %s /dev/i2c-0|1|2 r str\n", argv[0]);
		return -1;
	}

	//第一步:打开节点
	file = open_i2c_dev(argv[1][0] - '0', filename, sizeof(filename), 0);
	if(file < 0)
	{
		printf("can't open %s\n", filename);
		return -1;
	}
	
	if(set_slave_addr(file, dev_addr, 1))
	{
		printf("can't set_slave_addr\n");
		return -1;
	}
	
	//第二步:I2C读写数据
	if(argv[2][0] == 'w')
	{
		//write
		str = argv[3];
        
        //这里添加一定的休眠时间,完成1字节数据传输后,EEPROM会进入一个写循环(需要时间)
		req.tv_sec  = 0;
		req.tv_nsec = 20000000; /* 20ms */

		while(*str)
		{
			//mem_addr, *str
			//mem_addr++, str++
			ret = i2c_smbus_write_byte_data(file, mem_addr, *str);
			if(ret)
			{
				printf("i2c_smbus_write_byte_data err\n");
				return -1;

			}
			//等待EEPROM写完数据
			nanosleep(&req, NULL);
			mem_addr++;
			str++;
		}
		ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end char
		if (ret)
		{
			printf("i2c_smbus_write_byte_data err\n");
			return -1;
		}

	}
	else
	{
		//read
		ret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);
		if (ret < 0)
		{
			printf("i2c_smbus_read_i2c_block_data err\n");
			return -1;
		}
		
		buf[31] = '\0';
		printf("get data: %s\n", buf);
	}
}

2. Compilación, efecto real

a. Configurar la cadena de herramientas de compilación cruzada

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin

B. Write Makefile: después de configurar la cadena de herramientas, make ejecutará el programa

all:
$(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c

   Los archivos de la biblioteca son útiles aquí: i2cbusses.c i2cbusses.h smbus.c

C. Prueba en máquina

//nfs挂载
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

//复制、执行程序
cp /mnt/at24c02_test /bin
at24c02_test 0 w helloworld
at24c02_test 0 r

Supongo que te gusta

Origin blog.csdn.net/weixin_42373086/article/details/130466485
Recomendado
Clasificación