Hola a todos:
Lo primero es agradecer las posibles respuestas que me podáis dar.
Os cuento mi problema. Estoy desarrollando un programa en C++, para la Raspberry, que hace uso de un LCD (Kit Adafruit LCD 16x2 ). Este LCD hace uso de un chip MCP23017 y se comunica con la Rasp mediante i2c. El caso es que existe una librería en Python para este LCD y lo que estoy intentando es traducirlo a C++.
La comunicación del sistema operativo (Raspbian) con i2c es mediante el uso de descriptores de ficheros. Compruebo que abro bien el fichero, pero a la hora de hacer operaciones con él me cambia el descriptor de fichero y no encuentro la causa.
Este es el resultado que obtengo:
root@raspberrypi:/liquidcrystal# ./prueba
openI2C - File Descriptor: 3
openI2C - File Descriptor: 3
i2c_smbus - File Descriptor: 0
Os copio la clase que controla el acceso a i2c.
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <string>
#include "i2c8Bit.h"
using namespace std;
/************************************************** ***************
* This is the default constructor for the class. It assigns
* all private variables to default values and calls the openI2C()
* function to open the default I2C device "/dev/i2c-0".
************************************************** ***************/
i2c8Bit::i2c8Bit(uint8_t dev_addr){
int revision = this->piBoardRev();
if (revision == 1) i2c8Bit(dev_addr, string("/dev/i2c-0"));
else if (revision == 2) i2c8Bit(dev_addr, string("/dev/i2c-1"));
else {printf("Error"); exit(1);}
}
/************************************************** *****************
* This is the overloaded constructor. It allows the programmer to
* specify a custom I2C device & device address
* The device descriptor is determined by the openI2C() private member
* function call.
* ************************************************** ***************/
i2c8Bit::i2c8Bit(uint8_t dev_addr, string i2c_file_name){
this->i2cFileName = i2c_file_name;
this->deviceAddress = dev_addr;
this->i2cDescriptor = 0;
this->openI2C();
}
/************************************************** ********************
* This is the class destructor it simply closes the open I2C device
* by calling the closeI2C() which in turn calls the close() system call
* ************************************************** *******************/
i2c8Bit::~i2c8Bit(void){
//cout << " Closing I2C Device" << endl;
this->closeI2C();
}
/************************************************** ********************
* This function opens the I2C device by simply calling the open system
* call on the I2C device specified in the i2cFileName string. The I2C
* device is opened for writing and reading. The i2cDescriptor private
* variable is set by the return value of the open() system call.
* This variable will be used to reference the opened I2C device by the
* ioctl() & close() system calls.
* ************************************************** ******************/
int i2c8Bit::openI2C(){
if (this->i2cDescriptor) this->closeI2C();
this->i2cDescriptor = open(this->i2cFileName.c_str(), O_RDWR);
if (this->i2cDescriptor < 0) {
perror("Could not open file");
exit(1);
}
if (ioctl(this->i2cDescriptor, I2C_SLAVE, this->deviceAddress) < 0)
{
perror("Unable to select I2C device");
exit(1);
}
printf("openI2C - File Descriptor: %i \n", this->i2cDescriptor);
return 0;
}
/************************************************** *******************
* This function closes the I2C device by calling the close() system call
* on the I2C device descriptor.
* ************************************************** *****************/
int i2c8Bit::closeI2C(){
int retVal = -1;
if (this->i2cDescriptor)
{
retVal = close(this->i2cDescriptor);
if(retVal < 0){
perror("Could not close file (1)");
exit(1);
}
this->i2cDescriptor = 0;
}
return retVal;
}
int i2c8Bit::piBoardRev (void)
{
FILE *cpuFd ;
char line [120] ;
char *c ;
static int boardRev = -1 ;
if (boardRev != -1) // No point checking twice
return boardRev ;
if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
{ perror("Unable to open /proc/cpuinfo"); exit(1); }
while (fgets (line, 120, cpuFd) != NULL)
if (strncmp (line, "Revision", 8) == 0)
break ;
fclose (cpuFd) ;
if (strncmp (line, "Revision", 8) != 0)
{ perror("No \"Revision\" line"); exit(1); }
// Chomp trailing CR/NL
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
// Scan to first digit
for (c = line ; *c ; ++c)
if (isdigit (*c))
break ;
if (!isdigit (*c))
{ perror("No numeric revision string"); exit(1); }
// Make sure its long enough
if (strlen (c) < 4)
{ perror("Bogus \"Revision\" line (too small)"); exit(1); }
// Isolate last 4 characters:
c = c + strlen (c) - 4 ;
if ( (strcmp (c, "0002") == 0) || (strcmp (c, "0003") == 0))
boardRev = 1 ;
else
boardRev = 2 ;
return boardRev ;
}
uint8_t i2c8Bit::i2cRead()
{
union i2c_smbus_data data ;
if (this->i2c_smbus_operation(I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)) return -1;
return data.byte & 0xFF;
}
uint8_t i2c8Bit::i2cReadReg8(uint8_t reg)
{
union i2c_smbus_data data;
if (this->i2c_smbus_operation(I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data)) return -1 ;
return data.byte & 0xFF;
}
uint16_t i2c8Bit::i2cReadReg16(uint8_t reg)
{
union i2c_smbus_data data;
if (this->i2c_smbus_operation(I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, &data)) return -1 ;
return data.word & 0xFFFF;
}
int i2c8Bit::i2cWrite(uint8_t data)
{
return this->i2c_smbus_operation(I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) ;
}
int i2c8Bit::i2cWriteList(uint8_t reg, uint8_t *value, int lenghtValue)
{
union i2c_smbus_data data;
data.block[0] = lenghtValue;
for(int i = 0; i < lenghtValue; i++)
data.block[i+1] = value;
// return this->i2c_smbus_operation(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BLOCK_DATA, &data);
return this->i2c_smbus_operation(I2C_SMBUS_WRITE, reg, I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
int i2c8Bit::i2cWriteReg8 (uint8_t reg, uint8_t value)
{
union i2c_smbus_data data;
data.byte = value ;
return this->i2c_smbus_operation(I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data) ;
//return this->writeReg(reg, value);
}
int i2c8Bit::i2cWriteReg16 (uint8_t reg, uint16_t value)
{
union i2c_smbus_data data ;
data.word = value ;
return this->i2c_smbus_operation(I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, &data) ;
}
int i2c8Bit::i2c_smbus_operation(char rw, uint8_t command, int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args ;
int operation;
args.read_write = rw ;
args.command = command ;
args.size = size ;
args.data = data ;
printf("i2c_smbus - File Descriptor: %i \n", this->i2cDescriptor);
operation = ioctl(this->i2cDescriptor, I2C_SMBUS, &args);
if (operation < 0)
{
perror("Unable to make operation"); exit(1);
}
return operation;
}
De nuevo, gracias a todos.
Saludos.