Работа с шиной I2C (TWI)

Функции этого раздела предназначены для обмена данными с периферийными устройствами по двухпроводному интерфейсу I2C (Inter-Integrated Circuit), также известному как TWI (Two-Wire Interface).

Доступность I2C-шин на Repka Pi 3 (SoC Allwinner H5):

Константа Интерфейс Пин SDA Пин SCL Доступен в вариантах распиновки
I2C1_BUS I2C1 PA12 (пин 3) PA11 (пин 5) 2-9
I2C2_BUS I2C2 PA19 (пин 27) PA18 (пин 28) 4

Доступность I2C-шин на Repka Pi 4 (SoC Allwinner H6):

Константа Интерфейс Пин SDA Пин SCL Доступен в вариантах распиновки
I2C1_BUS I2C1 PD26 (пин 3) PD25 (пин 5) 2-9
I2C2_BUS I2C2 PD24 (пин 27) PD23 (пин 28) 4
I2C3_BUS I2C3 PH6 (пин 21) PH5 (пин 19) 11

Доступность I2C-шин на Repka Pi 5

Константа

Интерфейс

Пин SDA

Пин SCL

Доступен в вариантах распиновки

I2C2_BUS

I2C2

GPIO1_B6_d (пин 27)

GPIO1_B7_u (пин 28)

4,8

I2C4_BUS

I2C4

GPIO0_C4_d (пин 10)

GPIO0_C5_u (пин 8)

8

I2C5_BUS

I2C5

GPIO3_D0_u (пин 40)

GPIO3_C7_u (пин 38)

8

I2C7_BUS

I2C7

GPIO4_B3_u (пин 15)

GPIO4_B2_u (пин 13)

8

I2C8_BUS

I2C8

GPIO1_D7_u (пин 3)

GPIO1_D6_u (пин 5)

2,3,4,7,8

i2cSetup() #

Инициализирует функцию передачи данных с использованием I2C интерфейса.

Синтаксис #

int i2cSetup(const int i2cBus, const int devId)

Параметры #

i2cBus - дескриптор порта I2C, доступные значения:

  • I2C1_BUS - порт I2C1.

  • I2C2_BUS - порт I2C2.

  • I2C3_BUS - порт I2C3 (I2CS на Repka Pi 4).

  • I2C4_BUS - порт I2C3 (I2CS на Repka Pi 5).

  • I2C5_BUS - порт I2C3 (I2CS на Repka Pi 5).

  • I2C7_BUS - порт I2C3 (I2CS на Repka Pi 5).

  • I2C8_BUS - порт I2C3 (I2CS на Repka Pi 5).

devId - Адрес slave-устройства на шине I2C.

Возврат #

Файловый дескриптор порта I2C.

i2cRelease() #

Высвобождает ресурсы задействованные функцией передачи данных с использованием I2C интерфейса.

Синтаксис #

int i2cRelease(int fd)

Параметры #

fd - Файловый дескриптор порта I2C.

Возврат #

Ничего.

i2cRead() #

Получает данные с устройства напрямую (без выполнения транзакции с регистрами).

Синтаксис #

int i2cRead(int fd)

Параметры #

fd - Файловый дескриптор порта I2C.

Возврат #

Данные полученные от устройства.

i2cReadReg8() #

Получает данные из 8-ми битного регистра устройства

Синтаксис #

int i2cReadReg8(int fd, int reg)

Параметры #

fd - Файловый дескриптор порта I2C.

reg - адрес 8-ми битного регистра.

Возврат #

Данные полученные из регистра устройства.

i2cReadReg16() #

Получает данные из 16-ти битного регистра устройства

Синтаксис #

int i2cReadReg16(int fd, int reg)

Параметры #

fd - Файловый дескриптор порта I2C.

reg - адрес 16-ти битного регистра.

Возврат #

Данные полученные из регистра устройства.

i2cWrite() #

Записывает данные в устройство напрямую (без выполнения транзакции с регистрами).

Синтаксис #

int i2cWrite(int fd, int data)

Параметры #

fd - Файловый дескриптор порта I2C.

data - данные передаваемые устройству.

Возврат #

0 при успешном выполнении, или отрицательное значение в случае ошибки.

i2cWriteReg8() #

Записывает данные в 8-ми битный регистр устройства.

Синтаксис #

int i2cWriteReg8(int fd, int reg, int data)

Параметры #

fd - Файловый дескриптор порта I2C.

reg - адрес 8-ми битного регистра.

data - данные передаваемые устройству.

Возврат #

0 при успешном выполнении, или отрицательное значение в случае ошибки.

i2cWriteReg16() #

Записывает данные в 16-ти битный регистр устройства.

Синтаксис #

int i2cWriteReg16(int fd, int reg, int data)

Параметры #

fd - Файловый дескриптор порта I2C.

reg - адрес 16-ти битного регистра.

data - данные передаваемые устройству.

Возврат #

0 при успешном выполнении, или отрицательное значение в случае ошибки.

Пример использования функций I2C: Подключение датчика температуры BMP280 #

Этот пример демонстрирует, как использовать функции i2cSetup, i2cRead и i2cRelease для настройки и получения данных от устройства по шине I2C.

Что делает этот пример:

  • Он последовательно подключиться по порту i2c.
  • Загрузит преднастройки для работы с датчиком.
  • В режиме реального времени будет опрашивать датчик и выдавать значение температуры окружающей среды.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#include "wiringRP.h"
#include "wire.h"

/*
Пример предназначен для иллюстрации возможности подключения устройств 
по протоколу I2C.
В данном примере подключается датчик температуры BMP280
и идет его опрос с интервалом в 1 секунду
*/

// Глобальные переменные и константы BMP280
int i2c1_fd;
const int   	PORT_I2C 	= I2C1_BUS;
const uint8_t	BMP280_ADR 	= 0x76;
const uint8_t	REG_CHIP_ID     = 0xD0;
const uint8_t   REG_CTRL_MEAS   = 0xF4;
const uint8_t   REG_CONFIG      = 0xF5;
const uint8_t   REG_DATA_START  = 0xF7;
const uint8_t   REG_CALIB_START = 0x88;
const uint8_t   REG_CALIB_END 	= 0xA1;

static uint8_t raw_data[32];
static uint8_t status;

static int T1;
static int T2;
static int T3;

static bool loadReg(uint8_t firstReg, uint8_t LastReg)
{
	for(uint8_t Ind = firstReg; Ind <= LastReg; Ind++)	{
		raw_data[Ind - firstReg] = i2cReadReg8(i2c1_fd, Ind);
		if(raw_data[Ind - firstReg] < 0) {
			printf("Регистр не доступен порт:%d регистр:%x\n", PORT_I2C, Ind);
			return false;
		}
	}
	return true;
}

void setup() {
    // Инициализация библиотек wiringRP
    if (setupWiringRP(WRP_MODE_SUNXI) < 0)
        goto error;
        
    // Инициализация пользовательских объектов
    i2c1_fd = i2cSetup(PORT_I2C, BMP280_ADR);

    if (i2c1_fd < 0) {
        goto error;
	}
	//Считываем регистры предустановки BME280
	if(!loadReg(REG_CALIB_START, REG_CALIB_END)) goto error;

	//Запоминаем предустановочные коэффициенты,
	//согласно datasheet BMP280
	T1 = raw_data[0] + (raw_data[1] << 8);
	T2 = raw_data[2] + (raw_data[3] << 8);
	T3 = raw_data[4] + (raw_data[5] << 8);
	
	/*	Записывает конфигурацию в управляющие регистры датчика.
	Устанавливает режим работы, частоту и точность измерений.
	Регистр CTRL_MEAS (0xF4):
	osrs_t = x1 (0b001), osrs_p = x1 (0b001), mode = normal (0b11)
	Итоговая команда: 0b00100111 = 0x27
	*/
	i2cWriteReg8(i2c1_fd, REG_CTRL_MEAS, 0x27);
	
/*	Регистр CONFIG (0xF5):
    t_sb = 1000ms (0b101), filter = off (0b000)
    Итоговая команда: 0b10100000 = 0xA0
*/        
	i2cWriteReg8(i2c1_fd, REG_CONFIG, 0xA0);
    return;

error:
    onClose(2);
}

void loop() {
    // Основной цикл программы
    // Считываем регистры текущего значения темпиратуры
    if(!loadReg(REG_DATA_START, REG_DATA_START + 5)) return;

	// расчет по предустановленным значениям
	//согласно datasheet BMP280 	
	int adc_P = (raw_data[0] << 12) | (raw_data[1] << 4) | (raw_data[2] >> 4);
	int adc_T = (raw_data[3] << 12) | (raw_data[4] << 4) | (raw_data[5] >> 4);
	
	int var1_t = (adc_T / 16384.0 - T1 / 1024.0) * T2;
	int var2_t = ((adc_T / 131072.0 - T1 / 8192.0) * (adc_T / 131072.0 - T1 / 8192.0)) * T3;
	int t_fine = var1_t + var2_t;
	int temperature = t_fine / 5120.0;
	printf("текущая темпиратура: %d\n", temperature);
   
    delay(1000);
}


ONDESTROY() {

    // Завершение работы библиотек
    i2cRelease(i2c1_fd);
    releaseWiringRP();
    exit(0);    // выход из программы
}

MAIN_WIRINGRP();
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#include "wiringRP.h"
#include "wire.h"

/*
Пример предназначен для иллюстрации возможности подключения устройств 
по протоколу I2C.
В данном примере подключается датчик температуры BMP280
и идет его опрос с интервалом в 1 секунду
*/

// Глобальные переменные и константы BMP280
int i2c1_fd;
const int   	PORT_I2C 	= I2C1_BUS;
const uint8_t	BMP280_ADR 	= 0x76;
const uint8_t	REG_CHIP_ID     = 0xD0;
const uint8_t   REG_CTRL_MEAS   = 0xF4;
const uint8_t   REG_CONFIG      = 0xF5;
const uint8_t   REG_DATA_START  = 0xF7;
const uint8_t   REG_CALIB_START = 0x88;
const uint8_t   REG_CALIB_END 	= 0xA1;

static uint8_t raw_data[32];
static uint8_t status;

static int T1;
static int T2;
static int T3;

static bool loadReg(uint8_t firstReg, uint8_t LastReg)
{
	for(uint8_t Ind = firstReg; Ind <= LastReg; Ind++)	{
		raw_data[Ind - firstReg] = i2cReadReg8(i2c1_fd, Ind);
		if(raw_data[Ind - firstReg] < 0) {
			printf("Регистр не доступен порт:%d регистр:%x\n", PORT_I2C, Ind);
			return false;
		}
	}
	return true;
}

void setup() {
    // Инициализация библиотек wiringRP
    if (setupWiringRP(WRP_MODE_SUNXI) < 0)
        goto error;
        
    // Инициализация пользовательских объектов
    i2c1_fd = i2cSetup(PORT_I2C, BMP280_ADR);

    if (i2c1_fd < 0) {
        goto error;
	}
	//Считываем регистры предустановки BME280
	if(!loadReg(REG_CALIB_START, REG_CALIB_END)) goto error;

	//Запоминаем предустановочные коэффициенты,
	//согласно datasheet BMP280
	T1 = raw_data[0] + (raw_data[1] << 8);
	T2 = raw_data[2] + (raw_data[3] << 8);
	T3 = raw_data[4] + (raw_data[5] << 8);
	
	/*	Записывает конфигурацию в управляющие регистры датчика.
	Устанавливает режим работы, частоту и точность измерений.
	Регистр CTRL_MEAS (0xF4):
	osrs_t = x1 (0b001), osrs_p = x1 (0b001), mode = normal (0b11)
	Итоговая команда: 0b00100111 = 0x27
	*/
	i2cWriteReg8(i2c1_fd, REG_CTRL_MEAS, 0x27);
	
/*	Регистр CONFIG (0xF5):
    t_sb = 1000ms (0b101), filter = off (0b000)
    Итоговая команда: 0b10100000 = 0xA0
*/        
	i2cWriteReg8(i2c1_fd, REG_CONFIG, 0xA0);
    return;

error:
    onClose(2);
}

void loop() {
    // Основной цикл программы
    // Считываем регистры текущего значения темпиратуры
    if(!loadReg(REG_DATA_START, REG_DATA_START + 5)) return;

	// расчет по предустановленным значениям
	//согласно datasheet BMP280 	
	int adc_P = (raw_data[0] << 12) | (raw_data[1] << 4) | (raw_data[2] >> 4);
	int adc_T = (raw_data[3] << 12) | (raw_data[4] << 4) | (raw_data[5] >> 4);
	
	int var1_t = (adc_T / 16384.0 - T1 / 1024.0) * T2;
	int var2_t = ((adc_T / 131072.0 - T1 / 8192.0) * (adc_T / 131072.0 - T1 / 8192.0)) * T3;
	int t_fine = var1_t + var2_t;
	int temperature = t_fine / 5120.0;
	printf("текущая темпиратура: %d\n", temperature);
   
    delay(1000);
}


ONDESTROY() {

    // Завершение работы библиотек
    i2cRelease(i2c1_fd);
    releaseWiringRP();
    exit(0);    // выход из программы
}

MAIN_WIRINGRP();
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#include "wiringRP.h"
#include "wire.h"

/*
Пример предназначен для иллюстрации возможности подключения устройств 
по протоколу I2C.
В данном примере подключается датчик температуры BMP280
и идет его опрос с интервалом в 1 секунду
*/

// Глобальные переменные и константы BMP280
int i2c1_fd;
const int   	PORT_I2C 		= I2C8_BUS;
const uint8_t	BMP280_ADR 		= 0x76;
const uint8_t	REG_CHIP_ID     = 0xD0;
const uint8_t   REG_CTRL_MEAS   = 0xF4;
const uint8_t   REG_CONFIG      = 0xF5;
const uint8_t   REG_DATA_START  = 0xF7;
const uint8_t   REG_CALIB_START = 0x88;
const uint8_t   REG_CALIB_END 	= 0xA1;

static uint8_t raw_data[32];
static uint8_t status;

static int T1;
static int T2;
static int T3;

static bool loadReg(uint8_t firstReg, uint8_t LastReg)
{
	for(uint8_t Ind = firstReg; Ind <= LastReg; Ind++)	{
		raw_data[Ind - firstReg] = i2cReadReg8(i2c1_fd, Ind);
		if(raw_data[Ind - firstReg] < 0) {
			printf("Регистр не доступен порт:%d регистр:%x\n", PORT_I2C, Ind);
			return false;
		}
	}
	return true;
}

void setup() {
    // Инициализация библиотек wiringRP
    if (setupWiringRP(WRP_MODE_SUNXI) < 0)
        goto error;
        
    // Инициализация пользовательских объектов
    i2c1_fd = i2cSetup(PORT_I2C, BMP280_ADR);

    if (i2c1_fd < 0) {
        goto error;
	}
	//Считываем регистры предустановки BME280
	if(!loadReg(REG_CALIB_START, REG_CALIB_END)) goto error;

	//Запоминаем предустановочные коэффициенты,
	//согласно datasheet BMP280
	T1 = raw_data[0] + (raw_data[1] << 8);
	T2 = raw_data[2] + (raw_data[3] << 8);
	T3 = raw_data[4] + (raw_data[5] << 8);
	
	/*	Записывает конфигурацию в управляющие регистры датчика.
	Устанавливает режим работы, частоту и точность измерений.
	Регистр CTRL_MEAS (0xF4):
	osrs_t = x1 (0b001), osrs_p = x1 (0b001), mode = normal (0b11)
	Итоговая команда: 0b00100111 = 0x27
	*/
	i2cWriteReg8(i2c1_fd, REG_CTRL_MEAS, 0x27);
	
/*	Регистр CONFIG (0xF5):
    t_sb = 1000ms (0b101), filter = off (0b000)
    Итоговая команда: 0b10100000 = 0xA0
*/        
	i2cWriteReg8(i2c1_fd, REG_CONFIG, 0xA0);
    return;

error:
    onClose(2);
}

void loop() {
    // Основной цикл программы
    // Считываем регистры текущего значения темпиратуры
    if(!loadReg(REG_DATA_START, REG_DATA_START + 5)) return;

	// расчет по предустановленным значениям
	//согласно datasheet BMP280 	
	int adc_P = (raw_data[0] << 12) | (raw_data[1] << 4) | (raw_data[2] >> 4);
	int adc_T = (raw_data[3] << 12) | (raw_data[4] << 4) | (raw_data[5] >> 4);
	
	int var1_t = (adc_T / 16384.0 - T1 / 1024.0) * T2;
	int var2_t = ((adc_T / 131072.0 - T1 / 8192.0) * (adc_T / 131072.0 - T1 / 8192.0)) * T3;
	int t_fine = var1_t + var2_t;
	int temperature = t_fine / 5120.0;
	printf("текущая темпиратура: %d\n", temperature);
   
    delay(1000);
}


ONDESTROY() {

    // Завершение работы библиотек
    i2cRelease(i2c1_fd);
    releaseWiringRP();
    exit(0);    // выход из программы
}

MAIN_WIRINGRP();

2899 views0 comments
0

Comments (0)

Sections

Navigation