alextnecc
Posts: 4
Joined: Thu Nov 10, 2016 9:55 pm

MCP23008 and Rpi in C

Thu Nov 10, 2016 10:21 pm

Please forgive me as I am relatively new to programming and am new to the RPi.
I am trying understand I2c communication and am not getting the correct output, I am trying to do this with as few libraries as possible and have had much success writing to the outputs. Reading from the inputs however has become a problem. My code sets up everything correctly as I can check with i2cget 1 0x20 0x09 and see the inputs working. But for some reason with running my code I am not getting the correct output and I am sure that it is something I am missing..
I am using read() and am really trying to keep things simple. Here is my code, let me know what you think could fix this:

Code: Select all

#include <linux/i2c-dev.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>

#define ADDR	0x20

#define	IODIR	0x00
#define	GPINTEN	0x02
#define	DEFVAL	0x03
#define	INTCON	0x04
#define	IOCON	0x05
#define GPPU	0x06
#define	INTCAP	0x08
#define	GPIOA	0x09

#define a(...) (unsigned char[])__VA_ARGS__
int i, fd, result;
unsigned char buffer[60]={0};
unsigned char data;

int MCPinit(){
	printf("start\n");

	fd = open("/dev/i2c-1", O_RDWR);
	if (fd < 0) fprintf(stderr," Error Opening Device!\n");
	
	result = ioctl(fd, I2C_SLAVE, ADDR);
	if (result < 0) fprintf(stderr," Error  bus access!\n");
	
	write(fd, a({GPIOA,0xF0}), 2);
	write(fd, a({IODIR,0xF0}), 2);
	write(fd, a({INTCON,0xF0}), 2);
	write(fd, a({DEFVAL,0xF0}), 2);
	write(fd, a({GPINTEN,0xF0}), 2);
	write(fd, a({GPPU,0xF0}), 2);
}

int main(){	
	MCPinit();

	while(1){
		read(fd,buffer, 2);
		printf("Data read: %s\n", buffer);
	}
	return 0;
}
Last edited by alextnecc on Thu Nov 10, 2016 11:02 pm, edited 1 time in total.

User avatar
joan
Posts: 14668
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: MCP23008 and Rpi in C

Thu Nov 10, 2016 10:40 pm

You should wrap code in

Code: Select all

 
quotes for legibility.

You are reading two bytes from the device and printing them as if they are a C string (which is a sequence of ASCII characters terminated with a null).

Perhaps print buffer[0] and buffer[1] instead?

alextnecc
Posts: 4
Joined: Thu Nov 10, 2016 9:55 pm

Re: MCP23008 and Rpi in C

Thu Nov 10, 2016 10:57 pm

When I do that the data is junk. I would like to read from data-address 0x09 and I'm not sure how to specify that. I should get a value of 0xF0 with no inputs. I'm really new at all this so please forgive my ignorance with the formatting.

User avatar
joan
Posts: 14668
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: MCP23008 and Rpi in C

Thu Nov 10, 2016 11:03 pm

alextnecc wrote:When I do that the data is junk. I would like to read from data-address 0x09 and I'm not sure how to specify that. I should get a value of 0xF0 with no inputs. I'm really new at all this so please forgive my ignorance with the formatting.
As a general rule when you want to read x bytes from register y of an I2C device.

1) write one byte with the value y to the device.
2) read x bytes from the device.

So try

Code: Select all

buf[0] = 9;
write(fd, buf, 1);
c = read(fd, buf, x);
if (c == x)
{
   /* good read */
}

alextnecc
Posts: 4
Joined: Thu Nov 10, 2016 9:55 pm

Re: MCP23008 and Rpi in C

Thu Nov 10, 2016 11:18 pm

That's perfect. I didn't get the part about writing the buffer first before the read.

Code: Select all

	while(1){
		buffer[0]=9;
		write(fd,buffer,1);
		result = read(fd,buffer, 2);
		if (result = 2){
			printf("Data read: %d\n", buffer[0]);
		}
	}

User avatar
joan
Posts: 14668
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: MCP23008 and Rpi in C

Fri Nov 11, 2016 8:48 am

I hope that means it worked.

As a general rule if an I2C device has multiple registers you write one byte to select the register and then read bytes to read the register. Also as a general rule if you read multiple bytes (in one read) the device will return the data from successive registers starting at the one you selected.

Of course you should confirm by reading the device datasheet. Although often terse the information is usually in the datasheet somewhere.

tito-t
Posts: 298
Joined: Thu Jan 07, 2016 5:14 pm

Re: MCP23008 and Rpi in C

Fri Nov 11, 2016 8:55 am

hello,
@alextnecc :

just out of interest:

is that true that you will be able to poll and view the input state bytes 0xF0 when you are printing

result = read(fd, buffer, 2); // read 2 bytes
printf("Data read: %d\n", buffer[0]); // print 1 byte

is it a 0x00 (lsb) what you see then?
but isn't there a 2nd byte (buffer[1]) to print, too ( msb=0x0F)

printf("Data read: %d %d \n", buffer[0], buffer[1] );

:?:
- Tim

alextnecc
Posts: 4
Joined: Thu Nov 10, 2016 9:55 pm

Re: MCP23008 and Rpi in C

Fri Nov 11, 2016 5:35 pm

That did work perfectly, the part that I forgot was writing the byte to select the register.
This selects the 0x09 (GPIO) register:

Code: Select all

	buffer[0]=9;
	write(fd,buffer,1);
And this reads the 2 bytes and prints:

Code: Select all

	result = read(fd,buffer,2);	
	if (result < 2) fprintf(stderr,"Read Failure\n");
        printf("Col: %d\n", buffer[0]);
I only need the 1st byte, I guess that I could clean up my code some.

djweis
Posts: 2
Joined: Fri Nov 25, 2016 1:51 am
Location: Iowa
Contact: Website

Re: MCP23008 and Rpi in C

Fri Nov 25, 2016 2:04 am

Also consider the wiringpi library. It has support for the MCP23008 and MCP23016 as well as a few other port expanders, LCD displays, etc.

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: MCP23008 and Rpi in C

Sat Nov 26, 2016 3:02 pm

djweis wrote:Also consider the wiringpi library. It has support for the MCP23008 and MCP23016 as well as a few other port expanders, LCD displays, etc.
the op said as few libraries as possible so I didn't contribute earlier, but fwiw, doing this in the wiringPi world goes like:

Code: Select all

#include <stdpio.h>
#include <mcp23008.h>

#define BASE_PIN 100
#define ADDR 0x20

main ()
{
  int res ;

  res = mcp23008Setup (BASE_PIN, ADDR) ;

  if (res < 0)
  {
    fprintf (stderr, "setup failed\n") ;
    exit (1) ;
  }

// Set the first pin to output and make it high

  pinMode (BASE_PIN, OUTPUT) ;
  digitalWrite (BASE_PIN, 1) ;

// Set the last pin to input and read 

  pinMode (BASE_PIN + 15, INPUT) ;
  printf ("Value is: %d\n", digitalRead (BASE_PIN + 15)) ;

  return 0 ;
}
compile with

Code: Select all

gcc test.c -lwiringPi
and run with:

Code: Select all

./a.out
-Gordon
--
Gordons projects: https://projects.drogon.net/

Stiller
Posts: 206
Joined: Fri Oct 14, 2016 9:03 am

Re: MCP23008 and Rpi in C

Mon Nov 28, 2016 10:33 am

just out of curiousity:
in the code above there are the includes
#include <stdpio.h>
#include <mcp23008.h>

on the wiringPi.com website instead, the codes include
#include <wiringPi.h>
#include <mcp23008.h>

there also is no news in wiringPi.com/news/ about a <stdpio.h> library (the latest entry is about version 2.29 from Sept. 2015)
- so is there a new API?
- what about the old #includes in recent programs - is it still backwards-compatible?

in case for recommendet updating to the new <stdpio.h> API (it this assumption should be true):
- how to update from the former version to the new one?
- just sudo apt-get update or upgrade?
- Or complete uninstall and reinstall?
- Or download and install and overwrite the old installation?

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: MCP23008 and Rpi in C

Mon Nov 28, 2016 10:36 am

Stiller wrote:just out of curiousity:
in the code above there are the includes
#include <stdpio.h>
#include <mcp23008.h>

on the wiringPi.com website instead, the codes include
#include <wiringPi.h>
#include <mcp23008.h>

there also is no news in wiringPi.com/news/ about a <stdpio.h> library (the latest entry is about version 2.29 from Sept. 2015)
wiringPi is not intended for people new to C.

<stdio.h> has been about for about 40 years now. It's a well established bit of C.

-Gordon
--
Gordons projects: https://projects.drogon.net/

Stiller
Posts: 206
Joined: Fri Oct 14, 2016 9:03 am

Re: MCP23008 and Rpi in C

Mon Nov 28, 2016 10:39 am

about stdio.h I had not asked, but you wrote stdpio.h - CMIIW
(and you dropped that <wiringPi.h> which probably caused the confusion additionally )

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: MCP23008 and Rpi in C

Mon Nov 28, 2016 10:46 am

Stiller wrote:about stdio.h I had not asked, but you wrote stdpio.h - CMIIW
(and you dropped that <wiringPi.h> which probably caused the confusion additionally )
huh? Oh. Right. I made a dyslectic typo. Thanks for reminding me how badly wired my brain is.
<plonk>
-Gordon
--
Gordons projects: https://projects.drogon.net/

Stiller
Posts: 206
Joined: Fri Oct 14, 2016 9:03 am

Re: MCP23008 and Rpi in C

Mon Nov 28, 2016 11:04 am

no problem, but please consider that my posts are neither meant to be offending nor even "obtuse" what you might have hinted between the lines in your reply before the last one - I am not completely new to C, I just try to understand things, sometimes puzzeld by typos, and nevertheless surely hampered by foreign language difficulties (perhaps transparent to native English speakers in case they once joined a German, Dutch, French, or Italian conversation).

gauravsharma0190
Posts: 125
Joined: Tue Oct 28, 2014 6:36 am

Re: MCP23008 and Rpi in C

Thu Dec 01, 2016 5:15 am

[email protected] wrote:
djweis wrote:Also consider the wiringpi library. It has support for the MCP23008 and MCP23016 as well as a few other port expanders, LCD displays, etc.
the op said as few libraries as possible so I didn't contribute earlier, but fwiw, doing this in the wiringPi world goes like:

Code: Select all

#include <stdpio.h>
#include <mcp23008.h>

#define BASE_PIN 100
#define ADDR 0x20

main ()
{
  int res ;

  res = mcp23008Setup (BASE_PIN, ADDR) ;

  if (res < 0)
  {
    fprintf (stderr, "setup failed\n") ;
    exit (1) ;
  }

// Set the first pin to output and make it high

  pinMode (BASE_PIN, OUTPUT) ;
  digitalWrite (BASE_PIN, 1) ;

// Set the last pin to input and read 

  pinMode (BASE_PIN + 15, INPUT) ;
  printf ("Value is: %d\n", digitalRead (BASE_PIN + 15)) ;

  return 0 ;
}
compile with

Code: Select all

gcc test.c -lwiringPi
and run with:

Code: Select all

./a.out
-Gordon
hey Gorden thanks for this great library.i am makig gui with wiring pi library but when i run gui it tells "you forgot sudo".
how to overcome this problem

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: MCP23008 and Rpi in C

Thu Dec 01, 2016 12:55 pm

gauravsharma0190 wrote: hey Gorden thanks for this great library.i am makig gui with wiring pi library but when i run gui it tells "you forgot sudo".
how to overcome this problem
It tells you that you have forgotten to use sudo... So use sudo:

Code: Select all

sudo ./myprog
However if that's not acceptable to you, then use the gpiomem interface and to use that, you need to set an environment variable: WIRINGPI_GPIOMEM - either at the terminal with the command:

Code: Select all

export WIRINGPI_GPIOMEM=1
(assuming you use BASH), or in your program with:

Code: Select all

  putenv ("WIRINGPI_GPIOMEM=1") ;
-Gordon
--
Gordons projects: https://projects.drogon.net/

Return to “C/C++”