Как читать и записывать значения GPIO с помощью inb() и outb()
У меня есть атомная плата с GPIO Fintek F75111. У меня есть информация от производителя, что адрес SMbus для доступа к чипу - 06EH.
Я пытаюсь читать и записывать значения в GPIO в Linux. У меня есть пример программы от производителя, написанный для Windows, который выглядит следующим образом.
#include “math.h”
#include “stdio.h”
#include “dos.h”
void main(void){
int SMB_PORT_AD = 0x400;
int SMB_DEVICE_ADD = 0x6E;
/*75111R’s Add=6eh */
//programming DIO as output //0:input 1:Output
/* Index 10, GPIO1x Output pin control */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x10,0xff); delay(10);
//programming DIO default LOW
/* Index 11, GPIO1x Output Data value */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x11,0x00); delay(10);
}
unsigned char SMB_Byte_READ (int SMPORT, int DeviceID, int REG_INDEX)
{
unsigned char SMB_R;
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID+1); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
SMB_R= inportb(SMPORT+05);
return SMB_R;
}
void SMB_Byte_WRITE(int SMPORT, int DeviceID, int REG_INDEX, int REG_DATA)
{
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+05, REG_DATA); /* read_byte */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
}
Я попытался перевести это в Linux совместимые функции inb() и outb(), и это то, что я получил.
#include <stdio.h>
#include <sys/io.h>
unsigned int gpio_read(int PORT, int DEVICE, int REG_INDEX){
unsigned int RESPONSE;
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE+1, PORT+04);
outb(REG_INDEX, PORT+03);
outb(0x48, PORT+02);
usleep(100);
RESPONSE = inb(PORT+05);
return RESPONSE;
}
unsigned int gpio_write(int PORT, int DEVICE, int REG_INDEX, int REG_DATA){
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE, PORT+04);
outb(REG_INDEX, PORT+03);
outb(DATA, PORT+05);
outb(0x48, PORT+02);
usleep(100);
}
void main() {
int PORT = 0x400;
int DEVICE = 0x6E;
unsigned int RESPONSE;
// Ask access to port from kernel
ioperm(0x400, 100, 1);
// GPIO1x set to input (0xff is output)
gpio_write(PORT, DEVICE, 0x10, 0x00);
RESPONSE = gpio_read(PORT, DEVICE, 1);
printf("\n %u \n", RESPONSE);
}
Индекс GPIO1X 0x10 используется для установки, если 8 портов GPIO, подключенных к GPIO1x, являются выходными или входными портами.
Выходные значения для GPIO устанавливаются с использованием индекса 0x11, и если порты работают как входные порты, то индекс 0x12 используется для чтения входных значений.
Проблема в том, что я не знаю, правильно ли это или как читать значения (почему функция чтения что-то выводит перед чтением?!?)
Когда я бегу:
RESPONSE = gpio_read(PORT, DEVICE, X);
Изменяя X со значениями от 1..9, я получаю это как вывод: 0 8 8 0 0 0 0 0 0
Число 8 смущает меня...
1 ответ
Вместо того, чтобы писать напрямую в порт SMBus, я бы предпочел использовать библиотеки i2c. I2C (и SMBUS) используют два контакта порта, один для часов и один для данных. Данные передаются и принимаются по краям часов (синхронно). Считывая код, я не вижу четко, к какому из них (часы или данные) обращаются и когда.
Для начала я бы использовал i2ctools в качестве отправной точки (проверьте этот сайт: http://elinux.org/Interfacing_with_I2C_Devices). Этот инструмент поможет вам найти устройства, подключенные к шине I2C к вашему микропроцессору, а также выполнить базовую связь.
Надеюсь, поможет...